//import org.apache.log4j.Logger; import org.apache.commons.lang.StringUtils; import java.util.Set; import java.util.HashSet; import java.util.StringTokenizer; import java.util.List; /** */ public class UserValidator { public static final int PHONE_NUMBER_MIN_LENGTH = 8; public static final int PASSWORD_MIN_LENGTH = 6; public static final int PASSWORD_MAX_LENGTH = 15; public static final int IMEISV_LENGTH = 17; public static final int IMEI_LENGTH = 15; // private static Logger logger = Logger.getLogger(UserValidator.class); private UserProductDao userProductDao; private AddressDao addressDao; private OperatorDao operatorDao; public UserValidator(UserProductDao userProductDao, AddressDao addressDao, OperatorDao operatorDao) { this.userProductDao = userProductDao; this.addressDao = addressDao; this.operatorDao = operatorDao; } public boolean validateApiUserForRegister(ApiUser apiUser, List<ApiStatusMessage> messages) { int initialSize = messages.size(); String email = apiUser.getEmailAddress(); if(isEmail(email)) { if(email.length() > User.EMAIL_ADDRESS_MAX_LENGTH) { messages.add(new ApiStatusMessage(EMAIL_ADDRESS_TOO_LONG_MESSAGE, EMAIL_ADDRESS_TOO_LONG)); } else { apiUser.setEmailAddress(email.toLowerCase()); } } else { messages.add(new ApiStatusMessage(INVALID_EMAIL_ADDRESS_MESSAGE, INVALID_EMAIL_ADDRESS)); } if(apiUser.getLocale() == null && apiUser.getLocationId() == null && (apiUser.getAddress() == null || apiUser.getAddress().getCountryCode() == null)) { messages.add(new ApiStatusMessage(LOCALE_IS_NULL_MESSAGE, LOCALE_IS_NULL)); } if(apiUser.getMsisdn() != null && !isPhoneNumber(apiUser.getMsisdn())) { messages.add(new ApiStatusMessage(INVALID_PHONE_NUMBER_MESSAGE, INVALID_PHONE_NUMBER)); } validateOperator(apiUser, messages); String gender = apiUser.getGender(); if(gender != null && !isGender(gender.toLowerCase())) { messages.add(new ApiStatusMessage( INVALID_GENDER_MESSAGE + ": " + gender, INVALID_GENDER)); } validateAddress(apiUser.getAddress(), messages); validatePhones(apiUser, messages); validateAccessories(apiUser, messages); ApiUserApplication currentApplication = apiUser.getCurrentApplication(); if(currentApplication != null) { validateApplicationAttributes(currentApplication.getAttributes(), messages); validateSubscriptions(currentApplication.getSubscriptions(), messages); } ApiUserApplication commonApplication = apiUser.getCommonApplication(); if(commonApplication != null) { validateApplicationAttributes(commonApplication.getAttributes(), messages); validateSubscriptions(commonApplication.getSubscriptions(), messages); } return messages.size() == initialSize; } private void validateOperator(ApiUser apiUser, List<ApiStatusMessage> messages) { ApiOperator apiOperator = apiUser.getOperator(); if(apiOperator == null || ( apiOperator.getName() == null && apiOperator.getOperatorId() == null)) { return; } if(apiOperator.getOperatorId() == null) { Operator operator = operatorDao.findOperatorByName(apiOperator.getName()); if(operator == null) { messages.add(new ApiStatusMessage(INVALID_OPERATOR_NAME_MESSAGE, INVALID_OPERATOR_NAME)); } else { apiOperator.setOperatorId(operator.getOperatorId()); } } else if(operatorDao.findOperatorByOperatorId(apiOperator.getOperatorId()) == null) { messages.add(new ApiStatusMessage(INVALID_OPERATOR_ID_MESSAGE, INVALID_OPERATOR_ID)); } } public boolean validateApiUserForUpdate(ApiUser apiUser, List<ApiStatusMessage> messages) { int initialSize = messages.size(); if(apiUser.getGender() != null) { String gender = apiUser.getGender().toLowerCase().trim(); if(!("".equals(gender) || UserValidator.isGender(gender))) { messages.add(new ApiStatusMessage( INVALID_GENDER_MESSAGE + ": " + apiUser.getGender(), INVALID_GENDER)); } } if(apiUser.getMsisdn() != null && !isPhoneNumber(apiUser.getMsisdn())) { messages.add(new ApiStatusMessage(INVALID_PHONE_NUMBER_MESSAGE, INVALID_PHONE_NUMBER)); } validateOperator(apiUser, messages); validateAddress(apiUser.getAddress(), messages); ApiUserApplication currentApplication = apiUser.getCurrentApplication(); if(currentApplication != null) { validateApplicationAttributes(currentApplication.getAttributes(), messages); validateSubscriptions(currentApplication.getSubscriptions(), messages); } ApiUserApplication commonApplication = apiUser.getCommonApplication(); if(commonApplication != null) { validateApplicationAttributes(commonApplication.getAttributes(), messages); validateSubscriptions(commonApplication.getSubscriptions(), messages); } validatePhones(apiUser, messages); validateAccessories(apiUser, messages); return messages.size() == initialSize; } public boolean validateEmailVerificationPolicy(VerificationPolicyRegisterUser policy, List<ApiStatusMessage> messages) { boolean valid; switch(policy.getEmailOption()) { case SEND_DEFAULT_ACTIVATION_EMAIL: valid = policy.getEmailVerificationStatus() == EmailVerificationStatus.NOT_VERIFIED || policy.getEmailVerificationStatus() == EmailVerificationStatus.VERIFICATION_IN_PROGRESS; break; case SEND_DEFAULT_CONFIRMATION_EMAIL: case SEND_NO_REGISTRATION_EMAIL: valid = policy.getEmailVerificationStatus() == EmailVerificationStatus.NOT_VERIFIED || policy.getEmailVerificationStatus() == EmailVerificationStatus.VERIFIED; break; case SEND_DEFAULT_BATCH_IMPORT_EMAIL: valid = policy.getEmailVerificationStatus() == EmailVerificationStatus.VERIFICATION_IN_PROGRESS || policy.getEmailVerificationStatus() == EmailVerificationStatus.VERIFIED; break; case SEND_CUSTOM_BATCH_IMPORT_EMAIL: valid = policy.getEmailVerificationStatus() == EmailVerificationStatus.VERIFICATION_IN_PROGRESS || policy.getEmailVerificationStatus() == EmailVerificationStatus.VERIFIED; valid &= policy.getCustomEmailMessagentId() != null; break; default: throw new RuntimeException("Unexpected new user option " + policy.getEmailOption()); } if(!valid) { messages.add(new ApiStatusMessage(INVALID_POLICY_REGISTER_USER_MESSAGE, INVALID_POLICY_REGISTER_USER)); } return valid; } public boolean validateEmailVerificationPolicy(VerificationPolicyUpdateUser policy, List<ApiStatusMessage> messages) { boolean valid = true; if(policy.getEmailOption() == EmailOptionUpdateUser.SEND_CUSTOM_WELCOME_EMAIL && policy.getWelcomeEmailMessagentId() == null) { valid = false; messages.add(new ApiStatusMessage(INVALID_POLICY_UPDATE_USER_MESSAGE, INVALID_POLICY_UPDATE_USER)); } return valid; } public boolean validatePhones(ApiUser apiUser, List<ApiStatusMessage> messages) { List<ApiPhone> phones = apiUser.getPhones(); if (phones == null || isDeleteMarker(phones)) { return true; } boolean success = true; for (ApiPhone phone : phones) { success &= validatePhone(phone, messages); } return success & validateOnePrimaryPhone(phones, messages); } /** * @param products The product list to test * @return true if the phone is a delete marker and false otherwise */ public boolean isDeleteMarker(List products) { if(products == null || products.size() != 1) return false; ApiProduct product = (ApiProduct) products.get(0); return product.getContentServicesId() == null && product.getName() == null && product.getGpdId() == 0; } public boolean validatePhone(ApiPhone apiPhone, List<ApiStatusMessage> messages) { boolean validPhone = true; String imei = apiPhone.getImei(); if(imei != null && !UserValidator.isIMEINumber(imei)) { messages.add(new ApiStatusMessage( INVALID_IMEI_NUMBER_MESSAGE + ": " + imei, INVALID_IMEI_NUMBER)); validPhone = false; } // use brand name as first choise vs. brandId String phoneBrandName = apiPhone.getBrandName(); short brandId = (short)apiPhone.getGpdBrandId(); if(StringUtils.isEmpty(phoneBrandName)) { phoneBrandName = userProductDao.getPhoneBrandName(brandId); if(phoneBrandName == null) { messages.add(new ApiStatusMessage( INVALID_PHONE_BRAND_ID_MESSAGE + ": " + apiPhone.getGpdBrandId(), INVALID_PHONE_BRAND_ID)); validPhone = false; } } else { brandId = userProductDao.getPhoneBrandId(phoneBrandName); } if(brandId == UserProductDao.UNKNOWN_PHONE_BRAND_ID) { messages.add(new ApiStatusMessage( INVALID_PHONE_BRAND_NAME_MESSAGE + ": " + phoneBrandName, INVALID_PHONE_BRAND_NAME)); validPhone = false; } return validPhone; } public boolean validateAccessories(ApiUser apiUser, List<ApiStatusMessage> messages) { List<ApiAccessory> accessories = apiUser.getAccessories(); if (accessories == null || isDeleteMarker(accessories)) { return true; } boolean success = true; for (ApiAccessory apiAccessory : accessories) { Product product = userProductDao.getProductByApiProduct(apiAccessory); if(product == null) { messages.add(new ApiStatusMessage( INVALID_ACCESSORY_MESSAGE, INVALID_ACCESSORY)); success = false; } } return success; } /** * Validates that the phones array contains exactly one phone which is primary OR no phones (null or zero length array). * A user does not have to have any phones. * * @param phones the phones to validate * @param messages the message collection to put possible error messages in * @return true if phones is null or empty, or if it contains exactly one primary phone */ public boolean validateOnePrimaryPhone(List<ApiPhone> phones, List<ApiStatusMessage> messages) { if(phones == null || phones.size() == 0) { return true; } boolean isValid = true; int primaryPhonesCount = 0; for (ApiPhone phone : phones) { if (phone.isPrimary()) { primaryPhonesCount++; } } if(primaryPhonesCount == 0) { isValid = false; messages.add(new ApiStatusMessage(NO_PRIMARY_PHONE_MESSAGE, NO_PRIMARY_PHONE)); } else if(primaryPhonesCount > 1) { isValid = false; messages.add(new ApiStatusMessage(MORE_THAN_ONE_PRIMARY_PHONE_MESSAGE, MORE_THAN_ONE_PRIMARY_PHONE)); } return isValid; } /** * Validates and AddressBean. * @param address The AddressBean to validate * @param messages the message collection to put possible error messages in * @return true if address is null or valid */ public boolean validateAddress(ApiAddress address, List<ApiStatusMessage> messages) { if(address == null) return true; boolean isValid = true; if(!isState(address.getUSState())) { isValid = false; messages.add(new ApiStatusMessage( INVALID_STATE_MESSAGE +": " + address.getUSState(), INVALID_STATE)); } if(!isCountryCode(address.getCountryCode())) { isValid = false; messages.add(new ApiStatusMessage( INVALID_COUNTRY_CODE_MESSAGE + ": " + address.getCountryCode(), INVALID_COUNTRY_CODE)); } return isValid; } public boolean isState(String state) { return state == null || "".equals(state.trim()) || addressDao.checkState(state); } public boolean isCountryCode(String countryCode) { return countryCode == null || "".equals(countryCode.trim()) || addressDao.checkCountryCode(countryCode); } /** * Verifies that application attribute keys are unique. * @param pairs The collection of aplication-specific attributes. * @param messages the message collection to put possible error messages in * @return true if pairs is a valid application attribute collection, otherwise false */ public boolean validateApplicationAttributes(List<ApiKeyValuePair> pairs, List<ApiStatusMessage> messages) { if(pairs == null) { // no attributes to create/update return true; } // if(pairs.size() == 1 && pairs.get(0).getKey() == null && pairs.get(0).getValue() == null) { // attempt to remove all attributes: accepted // return true; // } boolean isValid = true; Set<String> keys = new HashSet<String>(); for (ApiKeyValuePair pair : pairs) { if(pair == null) { messages.add(new ApiStatusMessage( APPLICATION_ATTRIBUTE_NULL_MESSAGE, APPLICATION_ATTRIBUTE_NULL)); isValid = false; continue; } String key = pair.getKey(); if(StringUtils.isEmpty(key)) { messages.add(new ApiStatusMessage( APPLICATION_ATTRIBUTE_KEY_IS_EMPTY_MESSAGE + ", key: " + key, APPLICATION_ATTRIBUTE_KEY_IS_EMPTY)); isValid = false; continue; } if(keys.contains(key)) { messages.add(new ApiStatusMessage( APPLICATION_ATTRIBUTE_KEY_NOT_UNIQUE_MESSAGE + ": " + key, APPLICATION_ATTRIBUTE_KEY_NOT_UNIQUE )); isValid = false; } keys.add(key); } return isValid; } /** * Verifies that application attribute keys are unique. * @param subscriptions The set of subscriptions. * @param messages the message collection to put possible error messages in * @return true if pairs is a valid application attribute collection, otherwise false */ public boolean validateSubscriptions(Set<Integer> subscriptions, List<ApiStatusMessage> messages) { if(subscriptions == null) { // no subscriptions to create/update return true; } if(subscriptions.size() == 1 && subscriptions.contains(0)) { // delete marker, attempt to remove all attributes: accepted return true; } boolean isValid = true; for (Integer subscription : subscriptions) { if(subscription <= 0) { messages.add(new ApiStatusMessage( INVALID_SUBSCRIPTION_ID_MESSAGE + ": " + subscription, INVALID_SUBSCRIPTION_ID)); isValid = false; } } return isValid; } /** * Validates that a string contains an email address. * These must be in the format [email protected] * @param input The email address * @return True if the input is an email address. */ public static boolean isEmail(String input) { if(input == null) return false; // Divide string into two elements around the hyhpen StringTokenizer tokenizerAt = new StringTokenizer(input, "@"); // Accept only one @-character, two elements if (tokenizerAt.countTokens() != 2) return false; // First (local) part of address // Cannot contain controls or space chars String firstElement = (String) tokenizerAt.nextElement(); char[] firstChars = firstElement.toCharArray(); for (char aChar : firstChars) { if (Character.isISOControl(aChar) || Character.isSpaceChar(aChar)) { return false; } } // Second (domain) part of address String secondElement = (String) tokenizerAt.nextElement(); // Must not start or end with periods if (isPeriod(secondElement.charAt(0))) return false; if (isPeriod(secondElement.charAt(secondElement.length() - 1))) return false; // Divide into sub-domains StringTokenizer tokenizerPeriod = new StringTokenizer(secondElement, "."); // Must be at least two elements // Note: This is not necessary according to RFC822 but a much // more realistic test if (tokenizerPeriod.countTokens() < 2) return false; // Each domain cannot contain controls or space chars while (tokenizerPeriod.hasMoreElements()) { String element = (String) tokenizerPeriod.nextElement(); char[] domainChars = element.toCharArray(); for (char aChar : domainChars) { if (Character.isISOControl(aChar) || Character.isSpaceChar(aChar)) { return false; } } } return true; } /** * A valid phone number starts with '+' sign and is followed by at least 8 digits. * @param input The phone number * @return True if the input is a valid phone number */ public static boolean isPhoneNumber(String input) { return input != null && input.startsWith("+") && StringUtils.isNumeric(input.substring(1)) && input.length() > PHONE_NUMBER_MIN_LENGTH; } /** * * @param input Supposed to contain a positive long * @return True if the input is a positive long */ public static boolean isPositiveLong(String input) { if(input == null) return false; try { long locationId = Long.parseLong(input); if(locationId < 0) return false; } catch(NumberFormatException e) { return false; } return true; } /** * A valid password has the following properties: * * <ul> * <li>it is between 6 and 15 characters long</li> * <li>it contains at least one letter and at least one digit</li> * <li>it does not contain white space</li> * </ul> * * @param input The password to be verified * @return true if input is a password, false otherwise */ public static boolean isPassword(String input) { if (input == null || input.length() < PASSWORD_MIN_LENGTH || input.length() > PASSWORD_MAX_LENGTH) { return false; } boolean someLetters = false; boolean someDigits = false; for (int i = 0; i < input.length(); ++i) { char ch = input.charAt(i); if (Character.isLetter(ch)) { someLetters = true; } else if(Character.isDigit(ch)){ someDigits = true; } else if (Character.isWhitespace(input.charAt(i))) return false; } return someLetters && someDigits; } /** * Accept 15 (IMEI with checksum), 16 digits(IMEISV without checksum with software version) and * 17 digits (IMEISV with checksum and software version), along with any number of hyphens ('-'). * * @param number The IMEI number to validate * @return true if the number is valid, false otherwise. */ public static boolean isIMEINumber(String number) { if(number == null) return false; String stripped = number.replaceAll("-",""); stripped = stripped.replaceAll(" ",""); if(!StringUtils.isNumeric(stripped)) { return false; } else if(stripped.length() == IMEI_LENGTH) { return checkIMEINumber(stripped); } else if(stripped.length() == IMEISV_LENGTH) { return checkIMEINumber(stripped.substring(0, IMEI_LENGTH)); } else if(stripped.length() == IMEISV_LENGTH -1) { return true; } return false; } /** * Checks whether a string of digits is a valid IMEI number according * to the Luhn algorithm, see [url=http://en.wikipedia.org/wiki/Luhn_algorithm]http://en.wikipedia.org/wiki/Luhn_algorithm[/url] * * 1. Starting with the second to last digit and moving left, double the * value of all the alternating digits. For any digits that thus become * 10 or more, add their digits together. For example, 1111 becomes 2121, * while 8763 becomes 7733 (from (1+6)7(1+2)3). * * 2. Add all these digits together. For example, 1111 becomes 2121, then * 2+1+2+1 is 6; while 8763 becomes 7733, then 7+7+3+3 is 20. * * 3. If the total ends in 0 (put another way, if the total modulus 10 is * 0), then the number is valid according to the Luhn formula, else it is * not valid. So, 1111 is not valid (as shown above, it comes out to 6), * while 8763 is valid (as shown above, it comes out to 20). * * @param number the IMEI number to validate. * @return true if the number is valid, false otherwise. */ public static boolean checkIMEINumber(String number) { int sum = 0; boolean alternate = false; for (int i = number.length() - 1; i >= 0; i--) { int digit; try { digit = Integer.parseInt(number.substring(i, i + 1)); } catch (NumberFormatException e) { return false; } if (alternate) { digit *= 2; if (digit > 9) { digit = (digit % 10) + 1; } } sum += digit; alternate = !alternate; } return (sum % 10 == 0); } public static boolean isGender(String input) { return input != null && (input.equals(FEMALE_GENDER) || input.equals(MALE_GENDER)); } // Private helper methods private static boolean isPeriod(char aChar) { return areEqual(aChar, '.'); } private static boolean areEqual(char left, char right) { return new Character(left).compareTo(right) == 0; } }
Mod Edit: Fixed code tags:
