package gw.solr.mapper uses com.guidewire.util.phonenumber.GWPhoneNumberUtil uses com.google.i18n.phonenumbers.NumberParseException uses com.google.i18n.phonenumbers.Phonenumber.PhoneNumber uses gw.api.system.PLLoggerCategory uses gw.api.util.PhoneUtil uses gw.api.util.phone.GWPhoneNumberBuilder uses gw.solr.utils.PLSolrUtils uses gw.xsd.config.solr_search_config.DataProperty uses gw.xsd.config.solr_search_config.ResultField uses org.json.simple.JSONArray uses java.lang.Long uses java.lang.NumberFormatException uses java.lang.StringBuffer uses java.util.List uses java.util.Stack uses java.util.regex.Pattern @ReadOnly class BuildPhones implements ISolrIndexMapper, ISolrQueryMapper, ISolrQueryResultMapper { final static var NORMALIZER = "[^\\d]" final static var NORMALIZER_PATTERN = Pattern.compile(NORMALIZER, Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE) /** * Phone numbers are normalized by Solr index pipeline. * (See gw_phone definition in schema.xml) * * @param inputDataProperties array of entity properties * @param beanMap map mapping names of beans to beans * @return JSONArray of phone number strings or null if no phone numbers */ override function mapIndex(inputDataProperties: List, dataHolder: IDataHolder): JSONArray { var phoneList = new JSONArray() for (idp in inputDataProperties) { var phoneBuilder = new GWPhoneNumberBuilder() var nationalSubscriberNumber = dataHolder.lookup(idp) phoneBuilder.withNationalNumber(nationalSubscriberNumber) var parameters = idp.DataProperty for (childParameter in parameters) { if (childParameter.Property.equals("phonecountrycodeProperty")) { var countryCode = dataHolder.lookup(childParameter) phoneBuilder.withCountryCode(countryCode) } else if (childParameter.Property.equals("extensionProperty")) { var extension = dataHolder.lookup(childParameter) phoneBuilder.withExtension(extension) } } var gwPhone = phoneBuilder.build() if (gwPhone != null) { var phone = gwPhone.formatIntlWithLocalizedExtension() if (phone != null && phone.length() > 0) { phoneList.add(phone) } } } return phoneList.size() > 0 ? phoneList : null } /** * Maps entered phone number to query term. Value is encoded according to * this field's encoder and also normalized by Solr query pipeline * (See gw_phone definition in schema.xml) * * @return raw phone number string entered by user or null */ override function mapQuery(queryDataProperties: List, dataHolder: IDataHolder): String { PLSolrUtils.validate(queryDataProperties.Count == 1, "Phone query mapper only supports a single criterion.") return dataHolder.lookup(queryDataProperties.get(0)) } /** * Phones column is not sortable */ override function mapSortColumn(resultFields: List, criteriaProperties: List, dataHolder: IDataHolder): String { return null } /** * Map the proper phone number from Solr response to a result field. Specifically, if * a phone number was used as a search criterion and produced a match, then map this value. * Otherwise, map the first phone number, if any, in the result set into the result field. *

* This version handles US locales only * * @return single phone number or empty string */ override function mapQueryResult(resultFields: List, criteriaProperties: List, dataHolder: IDataHolder, solrResult: IResultHolder): Object { PLSolrUtils.validate(resultFields.Count == 1, "Phone query result mapper only supports a single target field.") PLSolrUtils.validate(criteriaProperties.Count == 1, "Phone query result mapper only supports a single criterion.") var queriedPhoneNumber = dataHolder.lookup(criteriaProperties.get(0)) if (queriedPhoneNumber != null) { try { try { var phone = GWPhoneNumberUtil.getInstance().parseAndKeepRawInput(queriedPhoneNumber, PhoneUtil.UserDefaultPhoneCountry.Code) if (phone.CountryCodeSource == PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN) { queriedPhoneNumber = Long.valueOf(phone.getNationalNumber()).toString() } else { queriedPhoneNumber = Long.valueOf(normalize(queriedPhoneNumber)).toString() } } catch (f: NumberParseException) { queriedPhoneNumber = Long.valueOf(normalize(queriedPhoneNumber)).toString() } } catch (e: NumberFormatException) { queriedPhoneNumber = null PLLoggerCategory.SOLR_QUERY.trace("Failed to normalize queried phone number", e) } } var candidate: String = null var phoneStack = new Stack() var phones = solrResult.lookup(resultFields.get(0)) for (p in phones) { if (p typeis String && p?.HasContent) { try { // normalize result from solr var normalizedResult = Long.valueOf(GWPhoneNumberUtil.getInstance() .parse(p, PhoneUtil.DefaultPhoneCountryCode.Code).getNationalNumber()).toString() // Compare normalized result from solr with normalized input query if (normalizedResult.equals(queriedPhoneNumber)) { candidate = p break } // push original value into phoneStack instead of normalized value, this allows for reformatting via the user's default phone country phoneStack.push(p) } catch (e: NumberParseException) { PLLoggerCategory.SOLR_QUERY.trace("Failed to parse phone number returned from Solr index.", e) } } } // This should rarely happen after all the normalizations, but pop the top value if it does if (candidate == null && !phoneStack.Empty) { candidate = phoneStack.pop() } var returnedPhone = "" if (candidate != null) { // Use the user default country instead of server default country when you reformat the phone number returnedPhone = PhoneUtil.formatWithLocalizableExtension(candidate, PhoneUtil.UserDefaultPhoneCountry) } return returnedPhone } private function normalize(value: String): String { var sb = new StringBuffer(value.length()) var matcher = NORMALIZER_PATTERN.matcher(value) while (matcher.find()) { matcher.appendReplacement(sb, "") } matcher.appendTail(sb) return sb.toString() } }