diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/helpers/ExtensionHelper.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ExtensionUtil.java similarity index 52% rename from hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/helpers/ExtensionHelper.java rename to hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ExtensionUtil.java index 4cb5a9b08fb..4a55c23259e 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/helpers/ExtensionHelper.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ExtensionUtil.java @@ -1,33 +1,16 @@ -package ca.uhn.fhir.rest.server.interceptor.validation.helpers; +package ca.uhn.fhir.util; -/*- - * #%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.BaseRuntimeElementDefinition; import ca.uhn.fhir.context.FhirContext; import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBaseDatatype; import org.hl7.fhir.instance.model.api.IBaseExtension; import org.hl7.fhir.instance.model.api.IBaseHasExtensions; -public class ExtensionHelper { +/** + * Utility for modifying with extensions in a FHIR version-independent approach. + */ +public class ExtensionUtil { /** * Returns an extension with the specified URL creating one if it doesn't exist. @@ -37,9 +20,9 @@ public class ExtensionHelper { * @return Returns a extension with the specified URL. * @throws IllegalArgumentException IllegalArgumentException is thrown in case resource doesn't support extensions */ - public IBaseExtension getOrCreateExtension(IBase theBase, String theUrl) { + public static IBaseExtension getOrCreateExtension(IBase theBase, String theUrl) { IBaseHasExtensions baseHasExtensions = validateExtensionSupport(theBase); - IBaseExtension extension = getExtension(baseHasExtensions, theUrl); + IBaseExtension extension = getExtensionByUrl(baseHasExtensions, theUrl); if (extension == null) { extension = baseHasExtensions.addExtension(); extension.setUrl(theUrl); @@ -47,7 +30,7 @@ public class ExtensionHelper { return extension; } - private IBaseHasExtensions validateExtensionSupport(IBase theBase) { + private static IBaseHasExtensions validateExtensionSupport(IBase theBase) { if (!(theBase instanceof IBaseHasExtensions)) { throw new IllegalArgumentException(String.format("Expected instance that supports extensions, but got %s", theBase)); } @@ -61,7 +44,7 @@ public class ExtensionHelper { * @param theExtensionUrl URL of the extension * @return Returns true if extension is exists and false otherwise */ - public boolean hasExtension(IBase theBase, String theExtensionUrl) { + public static boolean hasExtension(IBase theBase, String theExtensionUrl) { IBaseHasExtensions baseHasExtensions; try { baseHasExtensions = validateExtensionSupport(theBase); @@ -69,7 +52,7 @@ public class ExtensionHelper { return false; } - return getExtension(baseHasExtensions, theExtensionUrl) != null; + return getExtensionByUrl(baseHasExtensions, theExtensionUrl) != null; } /** @@ -79,18 +62,18 @@ public class ExtensionHelper { * @param theExtensionUrl URL of the extension * @return Returns true if extension is exists and false otherwise */ - public boolean hasExtension(IBase theBase, String theExtensionUrl, String theExtensionValue) { + public static boolean hasExtension(IBase theBase, String theExtensionUrl, String theExtensionValue) { if (!hasExtension(theBase, theExtensionUrl)) { return false; } - IBaseDatatype value = getExtension((IBaseHasExtensions) theBase, theExtensionUrl).getValue(); + IBaseDatatype value = getExtensionByUrl((IBaseHasExtensions) theBase, theExtensionUrl).getValue(); if (value == null) { return theExtensionValue == null; } return value.toString().equals(theExtensionValue); } - private IBaseExtension getExtension(IBaseHasExtensions theBase, String theExtensionUrl) { + private static IBaseExtension getExtensionByUrl(IBaseHasExtensions theBase, String theExtensionUrl) { return theBase.getExtension() .stream() .filter(e -> theExtensionUrl.equals(e.getUrl())) @@ -98,18 +81,28 @@ public class ExtensionHelper { .orElse(null); } - public void setValue(IBaseExtension theExtension, String theValue, FhirContext theFhirContext) { - theExtension.setValue(newString(theValue, theFhirContext)); + /** + * Sets value of the extension + * + * @param theExtension The extension to set the value on + * @param theValue The value to set + * @param theFhirContext The context containing FHIR resource definitions + */ + public static void setExtension(FhirContext theFhirContext, IBaseExtension theExtension, String theValue) { + theExtension.setValue(TerserUtil.newElement(theFhirContext, "string", theValue)); } - public void setValue(IBase theBase, String theUrl, String theValue, FhirContext theFhirContext) { + /** + * Sets or replaces existing extension with the specified value + * + * @param theBase The resource to update extension on + * @param theUrl Extension URL + * @param theValue Extension value + * @param theFhirContext The context containing FHIR resource definitions + */ + public static void setExtension(FhirContext theFhirContext, IBase theBase, String theUrl, String theValue) { IBaseExtension ext = getOrCreateExtension(theBase, theUrl); - setValue(ext, theValue, theFhirContext); - } - - public IBaseDatatype newString(String theValue, FhirContext theFhirContext) { - BaseRuntimeElementDefinition def = theFhirContext.getElementDefinition("string"); - return (IBaseDatatype) def.newInstance(theValue); + setExtension(theFhirContext, ext, theValue); } } diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/helpers/BaseHelper.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/PropertyModifyingHelper.java similarity index 70% rename from hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/helpers/BaseHelper.java rename to hapi-fhir-base/src/main/java/ca/uhn/fhir/util/PropertyModifyingHelper.java index 0f7abdd3d9b..a92263cf29f 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/helpers/BaseHelper.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/PropertyModifyingHelper.java @@ -1,24 +1,4 @@ -package ca.uhn.fhir.rest.server.interceptor.validation.helpers; - -/*- - * #%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% - */ +package ca.uhn.fhir.util; import ca.uhn.fhir.context.FhirContext; import org.apache.commons.lang3.StringUtils; @@ -29,7 +9,11 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; -public class BaseHelper { +/** + * Helper class for handling updates of the instances that support property modification via setProperty + * and getProperty methods. + */ +public class PropertyModifyingHelper { public static final String GET_PROPERTY_METHOD_NAME = "getProperty"; public static final String SET_PROPERTY_METHOD_NAME = "setProperty"; @@ -41,7 +25,13 @@ public class BaseHelper { private FhirContext myFhirContext; - public BaseHelper(IBase theBase, FhirContext theFhirContext) { + /** + * Creates a new instance initializing the dependencies. + * + * @param theFhirContext FHIR context holding the resource definitions + * @param theBase The base class to set properties on + */ + public PropertyModifyingHelper(FhirContext theFhirContext, IBase theBase) { if (findGetPropertyMethod(theBase) == null) { throw new IllegalArgumentException("Specified base instance does not support property retrieval."); } @@ -49,6 +39,14 @@ public class BaseHelper { myFhirContext = theFhirContext; } + /** + * Gets the method with the specified name and parameter types. + * + * @param theObject Non-null instance to get the method from + * @param theMethodName Name of the method to get + * @param theParamClasses Parameters types that method parameters should be assignable as + * @return Returns the method with the given name and parameters or null if it can't be found + */ protected Method getMethod(Object theObject, String theMethodName, Class... theParamClasses) { for (Method m : theObject.getClass().getDeclaredMethods()) { if (m.getName().equals(theMethodName)) { @@ -69,6 +67,12 @@ public class BaseHelper { return null; } + /** + * Gets all non-blank fields as a single string joined with the delimiter provided by {@link #getDelimiter()} + * + * @param theFiledNames Field names to retrieve values for + * @return Returns all specified non-blank fileds as a single string. + */ public String getFields(String... theFiledNames) { return Arrays.stream(theFiledNames) .map(this::get) @@ -110,11 +114,10 @@ public class BaseHelper { } /** - * Gets property with the specified name from the provided base class. + * Gets property values with the specified name from the provided base class. * * @param thePropertyName Name of the property to get - * @return Returns property value converted to string. In case of multiple values, they are joined with the - * specified delimiter. + * @return Returns property values converted to string. */ public List getMultiple(String thePropertyName) { Method getPropertyMethod = findGetPropertyMethod(myBase); @@ -139,14 +142,29 @@ public class BaseHelper { return getMethod(theAddress, SET_PROPERTY_METHOD_NAME, theParamClasses); } + /** + * Gets the delimiter used when concatenating multiple field values + * + * @return Returns the delimiter + */ public String getDelimiter() { return myDelimiter; } + /** + * Sets the delimiter used when concatenating multiple field values + * + * @param theDelimiter The delimiter to set + */ public void setDelimiter(String theDelimiter) { this.myDelimiter = theDelimiter; } + /** + * Gets the base instance that this helper operates on + * + * @return Returns the base instance + */ public IBase getBase() { return myBase; } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/TerserUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/TerserUtil.java index adc6e11a2c7..1919029c736 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/TerserUtil.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/TerserUtil.java @@ -464,7 +464,6 @@ public final class TerserUtil { return (T) def.newInstance(); } - /** * Creates a new resource definition. * diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_server_interceptors.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_server_interceptors.md index b1768478819..f430e7367d5 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_server_interceptors.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_server_interceptors.md @@ -253,7 +253,7 @@ A sample configuration file can be found below: } ``` -Standardization can be disabled for a given request by providing ```HAPI-Standardization-Disabled``` request header. +Standardization can be disabled for a given request by providing ```HAPI-Standardization-Disabled: *``` request header. Header value can be any string, it is the presence of the header that disables the s13n. # Validation: Address Validation @@ -262,7 +262,7 @@ Standardization can be disabled for a given request by providing ```HAPI-Standar This interceptor is configured in ```address-validation.properties``` file that should be made available on the classpath. This file must contain ```validator.class``` property, which defines a fully qualified class implementing ```ca.uhn.fhir.rest.server.interceptor.validation.address.IAddressValidator``` interface. The specified implementation must provide service-specific logic for validating an Address instance. An example implementation can be found in ```ca.uhn.fhir.rest.server.interceptor.validation.address.impl.LoquateAddressValidator``` class which validates addresses by using Loquate Data Cleanse service. -Address validation can be disabled for a given request by providing ```HAPI-Address-Validation-Disabled``` request header. +Address validation can be disabled for a given request by providing ```HAPI-Address-Validation-Disabled: *``` request header. Header value can be any string, it is the presence of the header that disables the validation. # Validation: Field-Level Validation @@ -275,4 +275,4 @@ Address validation can be disabled for a given request by providing ```HAPI-Addr } ``` -Field validation can be disabled for a given request by providing ```HAPI-Field-Validation-Disabled``` request header. +Field validation can be disabled for a given request by providing ```HAPI-Field-Validation-Disabled: *``` request header. Header value can be any string, it is the presence of the header that disables the validation. diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/s13n/StandardizingInterceptor.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/s13n/StandardizingInterceptor.java index a3dbd45c17f..ba688e789d8 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/s13n/StandardizingInterceptor.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/s13n/StandardizingInterceptor.java @@ -23,9 +23,11 @@ package ca.uhn.fhir.rest.server.interceptor.s13n; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.fhirpath.FhirPathExecutionException; import ca.uhn.fhir.fhirpath.IFhirPath; +import ca.uhn.fhir.interceptor.api.Hook; +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.ServerOperationInterceptorAdapter; import ca.uhn.fhir.rest.server.interceptor.s13n.standardizers.EmailStandardizer; import ca.uhn.fhir.rest.server.interceptor.s13n.standardizers.FirstNameStandardizer; import ca.uhn.fhir.rest.server.interceptor.s13n.standardizers.IStandardizer; @@ -43,7 +45,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -public class StandardizingInterceptor extends ServerOperationInterceptorAdapter { +@Interceptor +public class StandardizingInterceptor { /** * Pre-defined standardizers @@ -85,13 +88,13 @@ public class StandardizingInterceptor extends ServerOperationInterceptorAdapter ourLog.info("Initialized standardizers {}", myStandardizers); } - @Override + @Hook(Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED) public void resourcePreCreate(RequestDetails theRequest, IBaseResource theResource) { ourLog.debug("Standardizing on pre-create for - {}, {}", theRequest, theResource); standardize(theRequest, theResource); } - @Override + @Hook(Pointcut.STORAGE_PRESTORAGE_RESOURCE_UPDATED) public void resourcePreUpdate(RequestDetails theRequest, IBaseResource theOldResource, IBaseResource theNewResource) { ourLog.debug("Standardizing on pre-update for - {}, {}, {}", theRequest, theOldResource, theNewResource); standardize(theRequest, theNewResource); @@ -166,7 +169,7 @@ public class StandardizingInterceptor extends ServerOperationInterceptorAdapter } private boolean appliesToResource(String theResourceFromConfig, String theActualResourceType) { - return theResourceFromConfig.equals("*") || theResourceFromConfig.equals(theActualResourceType); + return theResourceFromConfig.equals(theActualResourceType); } public Map> getConfig() { diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/s13n/standardizers/PhoneStandardizer.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/s13n/standardizers/PhoneStandardizer.java index 310e63d115b..f4598ee1fad 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/s13n/standardizers/PhoneStandardizer.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/s13n/standardizers/PhoneStandardizer.java @@ -21,7 +21,7 @@ package ca.uhn.fhir.rest.server.interceptor.s13n.standardizers; */ /** - * Standardizes phone numbers to fit 123-456-7890 patter. + * Standardizes phone numbers to fit 123-456-7890 pattern. */ public class PhoneStandardizer implements IStandardizer { diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/address/AddressValidatingInterceptor.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/address/AddressValidatingInterceptor.java index 2ac29059909..4851fc90c55 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/address/AddressValidatingInterceptor.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/address/AddressValidatingInterceptor.java @@ -23,10 +23,12 @@ package ca.uhn.fhir.rest.server.interceptor.validation.address; import ca.uhn.fhir.context.BaseRuntimeChildDefinition; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.RuntimeResourceDefinition; +import ca.uhn.fhir.interceptor.api.Hook; +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.ServerOperationInterceptorAdapter; -import ca.uhn.fhir.rest.server.interceptor.validation.helpers.ExtensionHelper; +import ca.uhn.fhir.util.ExtensionUtil; import org.apache.commons.lang3.Validate; import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBaseResource; @@ -38,7 +40,8 @@ import java.util.List; import java.util.Properties; import java.util.stream.Collectors; -public class AddressValidatingInterceptor extends ServerOperationInterceptorAdapter { +@Interceptor +public class AddressValidatingInterceptor { private static final Logger ourLog = LoggerFactory.getLogger(AddressValidatingInterceptor.class); @@ -47,8 +50,6 @@ public class AddressValidatingInterceptor extends ServerOperationInterceptorAdap public static final String ADDRESS_VALIDATION_DISABLED_HEADER = "HAPI-Address-Validation-Disabled"; - private ExtensionHelper myExtensionHelper = new ExtensionHelper(); - private IAddressValidator myAddressValidator; private Properties myProperties; @@ -92,13 +93,13 @@ public class AddressValidatingInterceptor extends ServerOperationInterceptorAdap } } - @Override + @Hook(Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED) public void resourcePreCreate(RequestDetails theRequest, IBaseResource theResource) { ourLog.debug("Validating address on for create {}, {}", theResource, theRequest); handleRequest(theRequest, theResource); } - @Override + @Hook(Pointcut.STORAGE_PRESTORAGE_RESOURCE_UPDATED) public void resourcePreUpdate(RequestDetails theRequest, IBaseResource theOldResource, IBaseResource theNewResource) { ourLog.debug("Validating address on for update {}, {}, {}", theOldResource, theNewResource, theRequest); handleRequest(theRequest, theNewResource); @@ -117,8 +118,8 @@ public class AddressValidatingInterceptor extends ServerOperationInterceptorAdap getAddresses(theResource, ctx) .stream() .filter(a -> { - return !myExtensionHelper.hasExtension(a, IAddressValidator.ADDRESS_VALIDATION_EXTENSION_URL) || - myExtensionHelper.hasExtension(a, IAddressValidator.ADDRESS_VALIDATION_EXTENSION_URL, IAddressValidator.EXT_UNABLE_TO_VALIDATE); + return !ExtensionUtil.hasExtension(a, IAddressValidator.ADDRESS_VALIDATION_EXTENSION_URL) || + ExtensionUtil.hasExtension(a, IAddressValidator.ADDRESS_VALIDATION_EXTENSION_URL, IAddressValidator.EXT_UNABLE_TO_VALIDATE); }) .forEach(a -> validateAddress(a, ctx)); } @@ -128,11 +129,11 @@ public class AddressValidatingInterceptor extends ServerOperationInterceptorAdap AddressValidationResult validationResult = getAddressValidator().isValid(theAddress, theFhirContext); ourLog.debug("Validated address {}", validationResult); - myExtensionHelper.setValue(theAddress, IAddressValidator.ADDRESS_VALIDATION_EXTENSION_URL, - validationResult.isValid() ? IAddressValidator.EXT_VALUE_VALID : IAddressValidator.EXT_VALUE_INVALID, theFhirContext); + ExtensionUtil.setExtension(theFhirContext, theAddress, IAddressValidator.ADDRESS_VALIDATION_EXTENSION_URL, + validationResult.isValid() ? IAddressValidator.EXT_VALUE_VALID : IAddressValidator.EXT_VALUE_INVALID); } catch (Exception ex) { ourLog.warn("Unable to validate address", ex); - myExtensionHelper.setValue(theAddress, IAddressValidator.ADDRESS_VALIDATION_EXTENSION_URL, IAddressValidator.EXT_UNABLE_TO_VALIDATE, theFhirContext); + ExtensionUtil.setExtension(theFhirContext, theAddress, IAddressValidator.ADDRESS_VALIDATION_EXTENSION_URL, IAddressValidator.EXT_UNABLE_TO_VALIDATE); } } diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/address/impl/LoquateAddressValidator.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/address/impl/LoquateAddressValidator.java index 39c0deb10c1..6a4e4521542 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/address/impl/LoquateAddressValidator.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/address/impl/LoquateAddressValidator.java @@ -109,7 +109,7 @@ public class LoquateAddressValidator extends BaseRestfulValidator { protected IBase toAddress(JsonNode match, FhirContext theFhirContext) { IBase addressBase = theFhirContext.getElementDefinition("Address").newInstance(); - AddressHelper helper = new AddressHelper(addressBase, theFhirContext); + AddressHelper helper = new AddressHelper(theFhirContext, addressBase); helper.setText(getString(match, "Address")); String str = getString(match, "Address1"); @@ -192,7 +192,7 @@ public class LoquateAddressValidator extends BaseRestfulValidator { } protected ObjectNode toJsonNode(IBase theAddress, ObjectMapper mapper, FhirContext theFhirContext) { - AddressHelper helper = new AddressHelper(theAddress, theFhirContext); + AddressHelper helper = new AddressHelper(theFhirContext, theAddress); ObjectNode addressNode = mapper.createObjectNode(); int count = 1; diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/address/impl/MelissaAddressValidator.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/address/impl/MelissaAddressValidator.java index aa6b7db9513..2a886487792 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/address/impl/MelissaAddressValidator.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/address/impl/MelissaAddressValidator.java @@ -60,7 +60,7 @@ public class MelissaAddressValidator extends BaseRestfulValidator { } protected Map getRequestParams(IBase theAddress) { - AddressHelper helper = new AddressHelper(theAddress, null); + AddressHelper helper = new AddressHelper(null, theAddress); Map requestParams = new HashMap<>(); requestParams.put("t", UUID.randomUUID().toString()); diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/fields/EmailValidator.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/fields/EmailValidator.java index a6fcdb053b7..cecc86457da 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/fields/EmailValidator.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/fields/EmailValidator.java @@ -24,11 +24,11 @@ import java.util.regex.Pattern; public class EmailValidator implements IValidator { - private Pattern myPattern = Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", + private Pattern myEmailPattern = Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE); @Override public boolean isValid(String theString) { - return myPattern.matcher(theString).matches(); + return myEmailPattern.matcher(theString).matches(); } } diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/fields/FieldValidatingInterceptor.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/fields/FieldValidatingInterceptor.java index 01b01bd0c46..76f5382da47 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/fields/FieldValidatingInterceptor.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/fields/FieldValidatingInterceptor.java @@ -22,6 +22,9 @@ package ca.uhn.fhir.rest.server.interceptor.validation.fields; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.fhirpath.IFhirPath; +import ca.uhn.fhir.interceptor.api.Hook; +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.ServerOperationInterceptorAdapter; @@ -34,7 +37,8 @@ import org.slf4j.LoggerFactory; import java.util.List; import java.util.Map; -public class FieldValidatingInterceptor extends ServerOperationInterceptorAdapter { +@Interceptor +public class FieldValidatingInterceptor { public enum ValidatorType { EMAIL; @@ -56,15 +60,15 @@ public class FieldValidatingInterceptor extends ServerOperationInterceptorAdapte myConfig = ConfigLoader.loadJson("classpath:field-validation-rules.json", Map.class); } - @Override + @Hook(Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED) public void resourcePreCreate(RequestDetails theRequest, IBaseResource theResource) { - ourLog.debug("Validating address on for create {}, {}", theResource, theRequest); + ourLog.debug("Validating address on create for resource {} / request {}", theResource, theRequest); handleRequest(theRequest, theResource); } - @Override + @Hook(Pointcut.STORAGE_PRESTORAGE_RESOURCE_UPDATED) public void resourcePreUpdate(RequestDetails theRequest, IBaseResource theOldResource, IBaseResource theNewResource) { - ourLog.debug("Validating address on for update {}, {}, {}", theOldResource, theNewResource, theRequest); + ourLog.debug("Validating address on update for resource {} / old resource {} / request {}", theOldResource, theNewResource, theRequest); handleRequest(theRequest, theNewResource); } diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/helpers/AddressHelper.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/helpers/AddressHelper.java index 6b86cc5633f..926ffe3f209 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/helpers/AddressHelper.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/validation/helpers/AddressHelper.java @@ -21,6 +21,7 @@ package ca.uhn.fhir.rest.server.interceptor.validation.helpers; */ import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.util.PropertyModifyingHelper; import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.instance.model.api.IBase; @@ -31,7 +32,7 @@ import java.util.stream.Collectors; /** * Helper class for working with FHIR Address element */ -public class AddressHelper extends BaseHelper { +public class AddressHelper extends PropertyModifyingHelper { public static final String FIELD_LINE = "line"; public static final String FIELD_CITY = "city"; @@ -46,8 +47,8 @@ public class AddressHelper extends BaseHelper { public static final String[] ADDRESS_PARTS = {FIELD_CITY, FIELD_DISTRICT, FIELD_STATE, FIELD_POSTAL}; - public AddressHelper(IBase theBase, FhirContext theFhirContext) { - super(theBase, theFhirContext); + public AddressHelper(FhirContext theFhirContext, IBase theBase) { + super(theFhirContext, theBase); } public String getCountry() { diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/address/AddressHelperTest.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/address/AddressHelperTest.java index f6641687343..25bc5faf117 100644 --- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/address/AddressHelperTest.java +++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/address/AddressHelperTest.java @@ -19,13 +19,13 @@ class AddressHelperTest { HumanName name = new HumanName(); name.setFamily("Test"); - final AddressHelper helper = new AddressHelper(name, null); + final AddressHelper helper = new AddressHelper(null, name); assertThrows(IllegalStateException.class, () -> { helper.getCountry(); }); assertThrows(IllegalArgumentException.class, () -> { - new AddressHelper(new StringType("this will blow up"), null); + new AddressHelper(null, new StringType("this will blow up")); }); } @@ -34,7 +34,7 @@ class AddressHelperTest { Address a = new Address(); a.setCountry("Test"); - AddressHelper helper = new AddressHelper(a, null); + AddressHelper helper = new AddressHelper(null, a); assertEquals("Test", helper.getCountry()); } @@ -43,7 +43,7 @@ class AddressHelperTest { Address a = new Address(); a.setCity("Hammer"); - AddressHelper helper = new AddressHelper(a, null); + AddressHelper helper = new AddressHelper(null, a); helper.setDelimiter("; "); assertEquals("Hammer", helper.getParts()); @@ -58,7 +58,7 @@ class AddressHelperTest { a.addLine("Unit 10"); a.setCity("Hammer"); - AddressHelper helper = new AddressHelper(a, null); + AddressHelper helper = new AddressHelper(null, a); assertEquals("Unit 10", helper.getLine()); a.addLine("100 Main St."); @@ -69,7 +69,7 @@ class AddressHelperTest { void testSetFields() { Address a = new Address(); - AddressHelper helper = new AddressHelper(a, ourContext); + AddressHelper helper = new AddressHelper(ourContext, a); helper.addLine("Line 1").addLine("Line 2"); helper.setCity("Hammer"); helper.setState("State"); diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/s13n/interceptors/StandardizingInterceptorTest.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/s13n/interceptors/StandardizingInterceptorTest.java index df839f0606a..a4cda65c723 100644 --- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/s13n/interceptors/StandardizingInterceptorTest.java +++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/s13n/interceptors/StandardizingInterceptorTest.java @@ -27,17 +27,10 @@ class StandardizingInterceptorTest { "\t\t\"Person.name.given\" : \"NAME_GIVEN\",\n" + "\t\t\"Person.telecom.where(system='phone').value\" : \"PHONE\"\n" + "\t\t},\n" + - "\t\"*\" : {\n" + - "\t\t\"telecom.where(system='email').value\" : \"EMAIL\"\n" + - "\t},\n" + "\t\"Patient\" : {\n" + "\t\t\"name.given\" : \"NAME_GIVEN\",\n" + "\t\t\"telecom.where(system='phone').value\" : \"PHONE\"\n" + - "\t\t},\n" + - "\t\"*\" : {\n" + - "\t\t\"telecom.where(system='email').value\" : \"EMAIL\"\n" + - "\t}\n" + - "\n" + + "\t\t}\n" + "}"; private static FhirContext ourCtx = FhirContext.forR4(); @@ -74,20 +67,7 @@ class StandardizingInterceptorTest { myInterceptor.resourcePreUpdate(myRequestDetails, null, p); - assertEquals("email@email.com", p.getTelecom().get(0).getValue()); + assertEquals(" Email@email.com", p.getTelecom().get(0).getValue(), "Expected email to remain the same"); assertEquals("123-456-7890", p.getTelecom().get(1).getValue()); } - - @Test - public void testUniversalOtherTypes() throws Exception { - Patient p = new Patient(); - p.addName().setFamily("FAM").addGiven("GIV"); - p.addTelecom().setSystem(ContactPoint.ContactPointSystem.EMAIL).setValue(" Test@TEST.com "); - - myInterceptor.resourcePreUpdate(myRequestDetails, null, p); - - assertEquals("Giv FAM", p.getName().get(0).getNameAsSingleString()); - assertEquals("test@test.com", p.getTelecom().get(0).getValue()); - } - } diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/util/ExtensionUtilTest.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/util/ExtensionUtilTest.java new file mode 100644 index 00000000000..6cc44d6985c --- /dev/null +++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/util/ExtensionUtilTest.java @@ -0,0 +1,24 @@ +package ca.uhn.fhir.util; + +import ca.uhn.fhir.context.FhirContext; +import org.hl7.fhir.r4.model.Patient; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasSize; +import static org.junit.jupiter.api.Assertions.*; + +class ExtensionUtilTest { + + private static final String EXT_URL = "http://magic.com/extensions"; + + private static FhirContext ourFhirContext = FhirContext.forR4(); + + @Test + void testExtensionsWork() { + Patient p1 = new Patient(); + assertFalse(ExtensionUtil.hasExtension(p1, EXT_URL)); + ExtensionUtil.setExtension(ourFhirContext, p1, EXT_URL, "value"); + assertTrue(ExtensionUtil.hasExtension(p1, EXT_URL)); + } +}