/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package edu.harvard.iq.dataverse; import edu.harvard.iq.dataverse.DatasetFieldType.FieldType; import edu.harvard.iq.dataverse.util.StringUtil; import java.net.MalformedURLException; import java.net.URL; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import javax.validation.Validation; import javax.validation.Validator; import javax.validation.ValidatorFactory; import org.apache.commons.lang.StringUtils; /** * * @author gdurand */ public class DatasetFieldValueValidator implements ConstraintValidator<ValidateDatasetFieldType, DatasetFieldValue> { private static final Logger logger = Logger.getLogger(DatasetFieldValueValidator.class.getCanonicalName()); //private String fieldType; public void initialize(ValidateDatasetFieldType constraintAnnotation) { //this.fieldType = constraintAnnotation.value(); } public boolean isValid(DatasetFieldValue value, ConstraintValidatorContext context) { context.disableDefaultConstraintViolation(); // we do this so we can have different messages depending on the different issue boolean lengthOnly = false; DatasetFieldType dsfType = value.getDatasetField().getDatasetFieldType(); FieldType fieldType = dsfType.getFieldType(); if (value.getDatasetField().getTemplate() != null){ lengthOnly = true; } if (value.getDatasetField().getParentDatasetFieldCompoundValue() != null && value.getDatasetField().getParentDatasetFieldCompoundValue().getParentDatasetField().getTemplate() != null ){ lengthOnly = true; } if (StringUtils.isBlank(value.getValue()) || StringUtils.equals(value.getValue(),DatasetField.NA_VALUE)) { return true; } if (fieldType.equals(FieldType.DATE) && !lengthOnly) { boolean valid = false; String testString = value.getValue(); if (!valid) { valid = isValidDate(testString, "yyyy-MM-dd"); } if (!valid) { valid = isValidDate(testString, "yyyy-MM"); } //If AD must be a 4 digit year if (value.getValue().contains("AD")) { testString = (testString.substring(0, testString.indexOf("AD"))).trim(); } String YYYYformat = "yyyy"; if (!valid ) { valid = isValidDate(testString, YYYYformat); if(!StringUtils.isNumeric(testString)){ valid = false; } } //If BC must be numeric if(!valid && value.getValue().contains("BC") ){ testString = (testString.substring(0, testString.indexOf("BC"))).trim(); if(StringUtils.isNumeric(testString)){ valid = true; } } // Validate Bracket entries // Must start with "[", end with "?]" and not start with "[-" if (!valid && value.getValue().startsWith("[") && value.getValue().endsWith("?]") && !value.getValue().startsWith("[-")) { testString = value.getValue().replace("[", " ").replace("?]", " ").replace("-", " ").replace("BC", " ").replace("AD", " ").trim(); if (value.getValue().contains("BC") && StringUtils.isNumeric(testString)) { valid = true; } else { valid = isValidDate(testString, YYYYformat); if (!StringUtils.isNumeric(testString)) { valid = false; } } } if (!valid) { // TODO: // This is a temporary fix for the early beta! // (to accommodate dates with time stamps from Astronomy files) // As a real fix, we need to introduce a different type - // "datetime" for ex. and use it for timestamps; // We do NOT want users to be able to enter a full time stamp // as the release date... // -- L.A. 4.0 beta valid = (isValidDate(value.getValue(), "yyyy-MM-dd'T'HH:mm:ss") || isValidDate(value.getValue(), "yyyy-MM-dd'T'HH:mm:ss.SSS") || isValidDate(value.getValue(), "yyyy-MM-dd HH:mm:ss")); } if (!valid ) { context.buildConstraintViolationWithTemplate(dsfType.getDisplayName() + " is not a valid date. \""+ YYYYformat + "\" is a supported format.").addConstraintViolation(); return false; } } if (fieldType.equals(FieldType.FLOAT) && !lengthOnly) { try { Double.parseDouble(value.getValue()); } catch (Exception e) { logger.fine("Float value failed validation: "+value.getValue()+" ("+dsfType.getDisplayName()+")"); context.buildConstraintViolationWithTemplate(dsfType.getDisplayName() + " is not a valid number.").addConstraintViolation(); return false; } } if (fieldType.equals(FieldType.INT) && !lengthOnly) { try { Integer.parseInt(value.getValue()); } catch (Exception e) { context.buildConstraintViolationWithTemplate(dsfType.getDisplayName() + " is not a valid integer.").addConstraintViolation(); return false; } } // Note, length validation for FieldType.TEXT was removed to accommodate migrated data that is greater than 255 chars. if (fieldType.equals(FieldType.URL) && !lengthOnly) { try { URL url = new URL(value.getValue()); } catch (MalformedURLException e) { context.buildConstraintViolationWithTemplate(dsfType.getDisplayName() + " " + value.getValue()+" is not a valid URL.").addConstraintViolation(); return false; } } if (fieldType.equals(FieldType.EMAIL) && !lengthOnly) { return EMailValidator.isEmailValid(value.getValue(), context); } return true; } private boolean isValidDate(String dateString, String pattern) { boolean valid=true; Date date; SimpleDateFormat sdf = new SimpleDateFormat(pattern); sdf.setLenient(false); try { dateString = dateString.trim(); date = sdf.parse(dateString); Calendar calendar = Calendar.getInstance(); calendar.setTime(date); int year = calendar.get(Calendar.YEAR); int era = calendar.get(Calendar.ERA); if (era == GregorianCalendar.AD ) { if ( year > 9999) { valid=false; } } }catch (ParseException e) { valid=false; } if (dateString.length()>pattern.length()) { valid=false; } return valid; } }