Updated standardization logic and removed obsolete validator
This commit is contained in:
parent
9e153ddbcd
commit
08934d2364
|
@ -44,7 +44,6 @@ import org.springframework.http.ResponseEntity;
|
|||
import javax.annotation.Nullable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Properties;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
@ -65,7 +64,7 @@ public class LoquateAddressValidator extends BaseRestfulValidator {
|
|||
protected static final String DEFAULT_DATA_CLEANSE_ENDPOINT = "https://api.addressy.com/Cleansing/International/Batch/v1.00/json4.ws";
|
||||
protected static final int MAX_ADDRESS_LINES = 8;
|
||||
|
||||
private Pattern myPattern = Pattern.compile("\\,(\\S)");
|
||||
private Pattern myCommaPattern = Pattern.compile("\\,(\\S)");
|
||||
|
||||
public LoquateAddressValidator(Properties theProperties) {
|
||||
super(theProperties);
|
||||
|
@ -128,7 +127,7 @@ public class LoquateAddressValidator extends BaseRestfulValidator {
|
|||
IBase addressBase = theFhirContext.getElementDefinition("Address").newInstance();
|
||||
|
||||
AddressHelper helper = new AddressHelper(theFhirContext, addressBase);
|
||||
helper.setText(getString(match, "Address"));
|
||||
helper.setText(standardize(getString(match, "Address")));
|
||||
|
||||
String str = getString(match, "Address1");
|
||||
if (str != null) {
|
||||
|
@ -217,14 +216,22 @@ public class LoquateAddressValidator extends BaseRestfulValidator {
|
|||
|
||||
String text = theNode.get(theField).asText();
|
||||
if (StringUtils.isEmpty(text)) {
|
||||
return text;
|
||||
return "";
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
Matcher m = myPattern.matcher(text);
|
||||
if (m.find()) {
|
||||
text = m.replaceAll(", $1");
|
||||
protected String standardize(String theText) {
|
||||
if (StringUtils.isEmpty(theText)) {
|
||||
return "";
|
||||
}
|
||||
return text.trim();
|
||||
|
||||
theText = theText.replaceAll("\\s\\s", ", ");
|
||||
Matcher m = myCommaPattern.matcher(theText);
|
||||
if (m.find()) {
|
||||
theText = m.replaceAll(", $1");
|
||||
}
|
||||
return theText.trim();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,145 +0,0 @@
|
|||
package ca.uhn.fhir.rest.server.interceptor.validation.address.impl;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR - Server Framework
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2021 Smile CDR, Inc.
|
||||
* %%
|
||||
* 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.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.server.interceptor.validation.address.AddressValidationException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.validation.address.AddressValidationResult;
|
||||
import ca.uhn.fhir.rest.server.interceptor.validation.helpers.AddressHelper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
|
||||
public class MelissaAddressValidator extends BaseRestfulValidator {
|
||||
|
||||
public static final String GLOBAL_ADDRESS_VALIDATION_ENDPOINT = "https://address.melissadata.net/v3/WEB/GlobalAddress/doGlobalAddress" +
|
||||
"?id={id}&a1={a1}&a2={a2}&ctry={ctry}&format={format}";
|
||||
|
||||
public MelissaAddressValidator(Properties theProperties) {
|
||||
super(theProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AddressValidationResult getValidationResult(AddressValidationResult theResult, JsonNode theResponse, FhirContext theFhirContext) {
|
||||
Response response = new Response(theResponse);
|
||||
theResult.setValid(response.isValidAddress());
|
||||
theResult.setValidatedAddressString(response.getAddress());
|
||||
return theResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResponseEntity<String> getResponseEntity(IBase theAddress, FhirContext theFhirContext) throws Exception {
|
||||
Map<String, String> requestParams = getRequestParams(theAddress);
|
||||
return newTemplate().getForEntity(getApiEndpoint(), String.class, requestParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getApiEndpoint() {
|
||||
String endpoint = super.getApiEndpoint();
|
||||
return StringUtils.isEmpty(endpoint) ? GLOBAL_ADDRESS_VALIDATION_ENDPOINT : endpoint;
|
||||
}
|
||||
|
||||
protected Map<String, String> getRequestParams(IBase theAddress) {
|
||||
AddressHelper helper = new AddressHelper(null, theAddress);
|
||||
|
||||
Map<String, String> requestParams = new HashMap<>();
|
||||
requestParams.put("t", UUID.randomUUID().toString());
|
||||
requestParams.put("id", getApiKey());
|
||||
requestParams.put("a1", helper.getLine());
|
||||
requestParams.put("a2", helper.getParts());
|
||||
requestParams.put("ctry", helper.getCountry());
|
||||
requestParams.put("format", "json");
|
||||
return requestParams;
|
||||
}
|
||||
|
||||
private static class Response {
|
||||
private JsonNode root;
|
||||
private JsonNode records;
|
||||
private JsonNode results;
|
||||
|
||||
private List<String> addressErrors = new ArrayList<>();
|
||||
private List<String> addressChange = new ArrayList<>();
|
||||
private List<String> geocodeStatus = new ArrayList<>();
|
||||
private List<String> geocodeError = new ArrayList<>();
|
||||
private List<String> addressVerification = new ArrayList<>();
|
||||
|
||||
public Response(JsonNode theRoot) {
|
||||
root = theRoot;
|
||||
|
||||
// see codes here - http://wiki.melissadata.com/index.php?title=Result_Codes
|
||||
String transmissionResults = root.get("TransmissionResults").asText();
|
||||
if (!StringUtils.isEmpty(transmissionResults)) {
|
||||
geocodeError.add(transmissionResults);
|
||||
throw new AddressValidationException(String.format("Transmission result %s indicate an error with the request - please check API_KEY", transmissionResults));
|
||||
}
|
||||
|
||||
int recordCount = root.get("TotalRecords").asInt();
|
||||
if (recordCount < 1) {
|
||||
throw new AddressValidationException("Expected at least one record in the address validation response");
|
||||
}
|
||||
|
||||
// get first match
|
||||
records = root.get("Records").get(0);
|
||||
results = records.get("Results");
|
||||
|
||||
// full list of response codes is available here
|
||||
// http://wiki.melissadata.com/index.php?title=Result_Code_Details#Global_Address_Verification
|
||||
for (String s : results.asText().split(",")) {
|
||||
if (s.startsWith("AE")) {
|
||||
addressErrors.add(s);
|
||||
} else if (s.startsWith("AC")) {
|
||||
addressChange.add(s);
|
||||
} else if (s.startsWith("GS")) {
|
||||
geocodeStatus.add(s);
|
||||
} else if (s.startsWith("GE")) {
|
||||
geocodeError.add(s);
|
||||
} else if (s.startsWith("AV")) {
|
||||
addressVerification.add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isValidAddress() {
|
||||
if (!geocodeError.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return addressErrors.isEmpty() && (geocodeStatus.contains("GS05") || geocodeStatus.contains("GS06"));
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
if (records == null) {
|
||||
return "";
|
||||
}
|
||||
if (!records.has("FormattedAddress")) {
|
||||
return "";
|
||||
}
|
||||
return records.get("FormattedAddress").asText("");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -125,9 +125,11 @@ class LoquateAddressValidatorTest {
|
|||
ObjectNode node = new ObjectNode(null, new HashMap<>());
|
||||
node.set("text1", new TextNode("This,Is,Text"));
|
||||
node.set("text2", new TextNode("This Is-Text,"));
|
||||
node.set("text3", new TextNode("This Is-Text with Invalid Formatting"));
|
||||
|
||||
assertEquals("This, Is, Text", myValidator.getString(node, "text1"));
|
||||
assertEquals("This Is-Text,", myValidator.getString(node, "text2"));
|
||||
assertEquals("This, Is, Text", myValidator.standardize(myValidator.getString(node, "text1")));
|
||||
assertEquals("This Is-Text,", myValidator.standardize(myValidator.getString(node, "text2")));
|
||||
assertEquals("This Is-Text, with Invalid Formatting", myValidator.standardize(myValidator.getString(node, "text3")));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -1,139 +0,0 @@
|
|||
package ca.uhn.fhir.rest.server.interceptor.validation.address.impl;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.server.interceptor.validation.address.AddressValidationException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.validation.address.AddressValidationResult;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.hl7.fhir.r4.model.Address;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
class MelissaAddressValidatorTest {
|
||||
|
||||
private static final String RESPONSE_INVALID_ADDRESS = "{\n" +
|
||||
" \"Version\": \"3.0.1.160\",\n" +
|
||||
" \"TransmissionReference\": \"1\",\n" +
|
||||
" \"TransmissionResults\": \"\",\n" +
|
||||
" \"TotalRecords\": \"1\",\n" +
|
||||
" \"Records\": [\n" +
|
||||
" {\n" +
|
||||
" \"RecordID\": \"1\",\n" +
|
||||
" \"Results\": \"AC01,AC12,AE02,AV12,GE02\",\n" +
|
||||
" \"FormattedAddress\": \"100 Main Street\",\n" +
|
||||
" \"Organization\": \"\",\n" +
|
||||
" \"AddressLine1\": \"100 Main Street\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
"}";
|
||||
|
||||
private static final String RESPONSE_VALID_ADDRESS = "{\n" +
|
||||
" \"Version\": \"3.0.1.160\",\n" +
|
||||
" \"TransmissionReference\": \"1\",\n" +
|
||||
" \"TransmissionResults\": \"\",\n" +
|
||||
" \"TotalRecords\": \"1\",\n" +
|
||||
" \"Records\": [\n" +
|
||||
" {\n" +
|
||||
" \"RecordID\": \"1\",\n" +
|
||||
" \"Results\": \"AC01,AV24,GS05\",\n" +
|
||||
" \"FormattedAddress\": \"100 Main St W;Hamilton ON L8P 1H6\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
"}";
|
||||
|
||||
private static final String RESPONSE_INVALID_KEY = "{\n" +
|
||||
" \"Version\": \"3.0.1.160\",\n" +
|
||||
" \"TransmissionReference\": \"1\",\n" +
|
||||
" \"TransmissionResults\": \"GE05\",\n" +
|
||||
" \"TotalRecords\": \"0\"\n" +
|
||||
"}";
|
||||
|
||||
private static FhirContext ourContext = FhirContext.forR4();
|
||||
|
||||
private MelissaAddressValidator myValidator;
|
||||
|
||||
@BeforeEach
|
||||
public void init() {
|
||||
Properties props = new Properties();
|
||||
props.setProperty(MelissaAddressValidator.PROPERTY_SERVICE_KEY, "MY_KEY");
|
||||
myValidator = new MelissaAddressValidator(props);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestBody() {
|
||||
Map<String, String> params = myValidator.getRequestParams(getAddress());
|
||||
|
||||
assertEquals("Line 1, Line 2", params.get("a1"));
|
||||
assertEquals("City, POSTAL", params.get("a2"));
|
||||
assertEquals("Country", params.get("ctry"));
|
||||
assertEquals("MY_KEY", params.get("id"));
|
||||
assertEquals("json", params.get("format"));
|
||||
assertTrue(params.containsKey("t"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServiceCalled() {
|
||||
Address address = getAddress();
|
||||
|
||||
final RestTemplate template = mock(RestTemplate.class);
|
||||
|
||||
Properties props = new Properties();
|
||||
props.setProperty(BaseRestfulValidator.PROPERTY_SERVICE_KEY, "MY_KEY");
|
||||
MelissaAddressValidator val = new MelissaAddressValidator(props) {
|
||||
@Override
|
||||
protected RestTemplate newTemplate() {
|
||||
return template;
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
val.getResponseEntity(address, ourContext);
|
||||
} catch (Exception e) {
|
||||
fail();
|
||||
}
|
||||
|
||||
verify(template, times(1)).getForEntity(any(String.class), eq(String.class), any(Map.class));
|
||||
}
|
||||
|
||||
private Address getAddress() {
|
||||
Address address = new Address();
|
||||
address.addLine("Line 1").addLine("Line 2").setCity("City").setPostalCode("POSTAL").setCountry("Country");
|
||||
return address;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccessfulResponses() throws Exception {
|
||||
AddressValidationResult res = myValidator.getValidationResult(new AddressValidationResult(),
|
||||
new ObjectMapper().readTree(RESPONSE_INVALID_ADDRESS), ourContext);
|
||||
assertFalse(res.isValid());
|
||||
|
||||
res = myValidator.getValidationResult(new AddressValidationResult(),
|
||||
new ObjectMapper().readTree(RESPONSE_VALID_ADDRESS), ourContext);
|
||||
assertTrue(res.isValid());
|
||||
assertEquals("100 Main St W;Hamilton ON L8P 1H6", res.getValidatedAddressString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testErrorResponses() throws Exception {
|
||||
assertThrows(AddressValidationException.class, () -> {
|
||||
myValidator.getValidationResult(new AddressValidationResult(),
|
||||
new ObjectMapper().readTree(RESPONSE_INVALID_KEY), ourContext);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue