/* * Copyright (C) 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package apps.provisioning.server.account; import java.util.HashMap; import java.util.Iterator; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import apps.provisioning.util.Utils; /** * Generates username suggestions. This is designed as an Iterator, so it can be controlled by * hasNext and next methods. */ public class UsernameIterator implements Iterator<String> { // Matches every pattern, where each pattern is a string like "[fieldName]" for any value of // "fieldName" (e.g., [firstname], [lastname], [studentId]) with optional "C#" in front // which indicates where to shorten the field (e.g., [C3_firstname] would be the first three // characters of the first name. // Also matches [#], which is used for an auto-incrementing number. private final Pattern PATTERN_REGEX = Pattern.compile("\\[(?:C(\\d+)_)?([#\\w]+)\\]"); private final String DEFAULT_PATTERN = "[C9_firstname][C9_lastname][#]"; private final String AUTONUMERIC_PATTERN = "[#]"; private final Logger logger = Logger.getLogger(UsernameIterator.class.getName()); private HashMap<String, String> userData; private Integer autonumeric; private Integer patternIndex; private String currentPattern; private String nextSuggestion; private String[] patterns; /** * Creates a UsernameIterator object. * * @param patterns The patterns to be evaluated as a String array. * @param userData The user information, the required fields are at least first name and last * name. * @throws Exception */ public UsernameIterator(String[] patterns, HashMap<String, String> userData) throws Exception { if (userData == null || patterns == null) { throw new Exception("The patterns and userData parameters can't be set as null."); } if (!userData.containsKey(UsernameManager.FIRST_NAME) || !userData.containsKey(UsernameManager.LAST_NAME)) { throw new Exception( "The userData parameter must cointain at least firstname and lastname fields."); } String firstname = userData.get(UsernameManager.FIRST_NAME); String lastname = userData.get(UsernameManager.LAST_NAME); if (firstname.length() > UsernameManager.MAX_NAME_LENGTH || lastname.length() > UsernameManager.MAX_NAME_LENGTH) { throw new Exception("One of the fields exceds the maximum length. 60 (firstname,lastname)."); } this.patterns = patterns; this.userData = userData; autonumeric = 1; patternIndex = 0; } /** * Retrieves the following pattern to be evaluated. If the pattern contains the autonumeric symbol * it returns the same pattern. */ private String getNextPattern() { if (currentPattern != null && currentPattern.contains(AUTONUMERIC_PATTERN)) { // Retrieves the previous generated pattern. return currentPattern; } if (patternIndex < patterns.length) { return patterns[patternIndex++]; } else { // No other pattern is available, so it returns the default. return DEFAULT_PATTERN; } } /** * Evaluates the current pattern and replaces the tags with user fields. * * @return Evaluated suggestion. */ private String processPattern() { currentPattern = getNextPattern(); String suggestion = currentPattern; Matcher matcher = PATTERN_REGEX.matcher(suggestion); String fieldValue = ""; while (matcher.find()) { String key = matcher.group(0); String fieldName = matcher.group(2); if (key.equals(AUTONUMERIC_PATTERN)) { fieldValue = "" + autonumeric++; } else { fieldValue = Utils.replaceSpecialChars(userData.get(fieldName)); if (fieldValue == null) { logger.log( Level.WARNING, "Field " + fieldName + " was not provided in the " + key + " pattern for user " + userData.get(UsernameManager.FIRST_NAME) + " " + userData.get(UsernameManager.LAST_NAME)); return processPattern(); } // Gets the matched string and retrieves the number of characters to be extracted. String substring_matcher = matcher.group(1); if (substring_matcher != null) { Integer characters = Integer.parseInt(substring_matcher); if (fieldValue.length() > characters) { fieldValue = fieldValue.substring(0, characters); } } } suggestion = matcher.replaceFirst(fieldValue); matcher.reset(suggestion); } if (suggestion.isEmpty()) { // This case happens when all the characters are invalid. return processPattern(); } return suggestion; } /** * Checks if the next element is not longer than 64 characters. */ public boolean hasNext() { nextSuggestion = processPattern(); if (currentPattern == DEFAULT_PATTERN && nextSuggestion.length() > UsernameManager.MAX_USERNAME_LENGTH) { logger.log(Level.WARNING, "The user name has exceeded the maximum length."); nextSuggestion = null; return false; } return true; } /** * Retrieves the next suggestion */ public String next() { if (nextSuggestion != null) { String next = nextSuggestion; nextSuggestion = null; return next; } return processPattern(); } /** * This is not necessary. */ public void remove() { throw new RuntimeException("Remove method doesn't apply to UsernameIterator."); } }