Initial commit
This commit is contained in:
parent
19ff4862ec
commit
961f16a1be
|
@ -31,7 +31,7 @@ public interface IAddressValidator {
|
|||
/**
|
||||
* URL for validation results that should be placed on addresses
|
||||
*/
|
||||
public static final String ADDRESS_VALIDATION_EXTENSION_URL = "https://hapifhir.org/AddressValidation/";
|
||||
public static final String ADDRESS_VALIDATION_EXTENSION_URL = "https://hapifhir.org/StructureDefinition/ext-validation-address-error";
|
||||
|
||||
/**
|
||||
* Extension value confirming that address can be considered valid (it exists and can be traced to the building)
|
||||
|
|
|
@ -37,6 +37,7 @@ import java.util.Properties;
|
|||
public abstract class BaseRestfulValidator implements IAddressValidator {
|
||||
|
||||
public static final String PROPERTY_SERVICE_KEY = "service.key";
|
||||
public static final String PROPERTY_SERVICE_ENDPOINT = "service.endpoint";
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(BaseRestfulValidator.class);
|
||||
|
||||
|
@ -97,4 +98,8 @@ public abstract class BaseRestfulValidator implements IAddressValidator {
|
|||
protected String getApiKey() {
|
||||
return getProperties().getProperty(PROPERTY_SERVICE_KEY);
|
||||
}
|
||||
|
||||
protected String getApiEndpoint() {
|
||||
return getProperties().getProperty(PROPERTY_SERVICE_ENDPOINT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import com.fasterxml.jackson.databind.JsonNode;
|
|||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -52,7 +53,7 @@ public class LoquateAddressValidator extends BaseRestfulValidator {
|
|||
|
||||
private static final String[] DUPLICATE_FIELDS_IN_ADDRESS_LINES = {"Locality", "AdministrativeArea", "PostalCode"};
|
||||
|
||||
private static final String DATA_CLEANSE_ENDPOINT = "https://api.addressy.com/Cleansing/International/Batch/v1.00/json4.ws";
|
||||
private static final String DEFAULT_DATA_CLEANSE_ENDPOINT = "https://api.addressy.com/Cleansing/International/Batch/v1.00/json4.ws";
|
||||
private static final int MAX_ADDRESS_LINES = 8;
|
||||
|
||||
public LoquateAddressValidator(Properties theProperties) {
|
||||
|
@ -171,7 +172,13 @@ public class LoquateAddressValidator extends BaseRestfulValidator {
|
|||
|
||||
String requestBody = getRequestBody(theFhirContext, theAddress);
|
||||
HttpEntity<String> request = new HttpEntity<>(requestBody, headers);
|
||||
return newTemplate().postForEntity(DATA_CLEANSE_ENDPOINT, request, String.class);
|
||||
return newTemplate().postForEntity(getApiEndpoint(), request, String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getApiEndpoint() {
|
||||
String endpoint = super.getApiEndpoint();
|
||||
return StringUtils.isEmpty(endpoint) ? DEFAULT_DATA_CLEANSE_ENDPOINT : endpoint;
|
||||
}
|
||||
|
||||
protected String getRequestBody(FhirContext theFhirContext, IBase... theAddresses) throws JsonProcessingException {
|
||||
|
|
|
@ -56,7 +56,13 @@ public class MelissaAddressValidator extends BaseRestfulValidator {
|
|||
@Override
|
||||
protected ResponseEntity<String> getResponseEntity(IBase theAddress, FhirContext theFhirContext) throws Exception {
|
||||
Map<String, String> requestParams = getRequestParams(theAddress);
|
||||
return newTemplate().getForEntity(GLOBAL_ADDRESS_VALIDATION_ENDPOINT, String.class, requestParams);
|
||||
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) {
|
||||
|
|
|
@ -27,7 +27,9 @@ import ca.uhn.fhir.interceptor.api.Interceptor;
|
|||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ConfigLoader;
|
||||
import ca.uhn.fhir.rest.server.interceptor.validation.address.IAddressValidator;
|
||||
import ca.uhn.fhir.util.ExtensionUtil;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseExtension;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -46,12 +48,11 @@ public class FieldValidatingInterceptor {
|
|||
private static final Logger ourLog = LoggerFactory.getLogger(FieldValidatingInterceptor.class);
|
||||
|
||||
public static final String VALIDATION_DISABLED_HEADER = "HAPI-Field-Validation-Disabled";
|
||||
|
||||
private IAddressValidator myAddressValidator;
|
||||
public static final String VALIDATION_EXTENSION_URL = "https://hapifhir.org/StructureDefinition/ext-validation-field-error";
|
||||
public static final String PROPERTY_EXTENSION_URL = "validation.extension.url";
|
||||
|
||||
private Map<String, String> myConfig;
|
||||
|
||||
|
||||
public FieldValidatingInterceptor() {
|
||||
super();
|
||||
|
||||
|
@ -84,20 +85,52 @@ public class FieldValidatingInterceptor {
|
|||
|
||||
FhirContext ctx = theRequest.getFhirContext();
|
||||
IFhirPath fhirPath = ctx.newFhirPath();
|
||||
|
||||
for (Map.Entry<String, String> e : myConfig.entrySet()) {
|
||||
IValidator validator = getValidator(e.getValue());
|
||||
if (validator == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<IPrimitiveType> values = fhirPath.evaluate(theResource, e.getKey(), IPrimitiveType.class);
|
||||
List<IBase> fields = fhirPath.evaluate(theResource, e.getKey(), IBase.class);
|
||||
for (IBase field : fields) {
|
||||
|
||||
List<IPrimitiveType> values = fhirPath.evaluate(field, "value", IPrimitiveType.class);
|
||||
boolean isValid = true;
|
||||
for (IPrimitiveType value : values) {
|
||||
String valueAsString = value.getValueAsString();
|
||||
if (!validator.isValid(valueAsString)) {
|
||||
throw new IllegalArgumentException(String.format("Invalid resource %s", valueAsString));
|
||||
isValid = validator.isValid(valueAsString);
|
||||
ourLog.debug("Field {} at path {} validated {}", value, e.getKey(), isValid);
|
||||
if (!isValid) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
setValidationStatus(ctx, field, isValid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setValidationStatus(FhirContext ctx, IBase theBase, boolean isValid) {
|
||||
if (isValid) {
|
||||
ExtensionUtil.clearExtensionsByUrl(theBase, getValidationExtensionUrl());
|
||||
} else {
|
||||
IBaseExtension<?, ?> validationResultExtension = ExtensionUtil.addExtension(theBase, getValidationExtensionUrl());
|
||||
ExtensionUtil.setExtension(ctx, theBase, getValidationExtensionUrl(), "boolean", Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
private String getValidationExtensionUrl() {
|
||||
if (myConfig.containsKey(PROPERTY_EXTENSION_URL)) {
|
||||
return myConfig.get(PROPERTY_EXTENSION_URL);
|
||||
}
|
||||
return VALIDATION_EXTENSION_URL;
|
||||
}
|
||||
|
||||
private IValidator getValidator(String theValue) {
|
||||
if (PROPERTY_EXTENSION_URL.equals(theValue)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (ValidatorType.EMAIL.name().equals(theValue)) {
|
||||
return new EmailValidator();
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"telecom.where(system='email').value" : "EMAIL"
|
||||
"telecom.where(system='email')" : "EMAIL"
|
||||
}
|
||||
|
|
|
@ -4,9 +4,12 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.r4.model.ContactPoint;
|
||||
import org.hl7.fhir.r4.model.Extension;
|
||||
import org.hl7.fhir.r4.model.Person;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
@ -19,6 +22,8 @@ import static org.mockito.Mockito.when;
|
|||
|
||||
class FieldValidatingInterceptorTest {
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(FieldValidatingInterceptorTest.class);
|
||||
|
||||
private FhirContext myFhirContext = FhirContext.forR4();
|
||||
private FieldValidatingInterceptor myInterceptor = new FieldValidatingInterceptor();
|
||||
|
||||
|
@ -61,12 +66,22 @@ class FieldValidatingInterceptorTest {
|
|||
public void testInvalidEmailValidation() {
|
||||
Person person = new Person();
|
||||
person.addTelecom().setSystem(ContactPoint.ContactPointSystem.EMAIL).setValue("@garbage");
|
||||
person.addTelecom().setSystem(ContactPoint.ContactPointSystem.EMAIL).setValue("my@email.com");
|
||||
|
||||
try {
|
||||
myInterceptor.handleRequest(newRequestDetails(), person);
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
fail();
|
||||
}
|
||||
|
||||
ourLog.info("Resource looks like {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(person));
|
||||
|
||||
ContactPoint invalidEmail = person.getTelecomFirstRep();
|
||||
assertTrue(invalidEmail.hasExtension());
|
||||
assertEquals("true", invalidEmail.getExtensionString("https://hapifhir.org/StructureDefinition/ext-validation-field-error"));
|
||||
|
||||
ContactPoint validEmail = person.getTelecom().get(1);
|
||||
assertFalse(validEmail.hasExtension());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue