Fix #534: Add setting for logical references to DAOConfig
Merge branch 'master' into issue534
This commit is contained in:
commit
2c9a6e65e7
|
@ -45,7 +45,7 @@ public interface ISort<T> {
|
|||
/**
|
||||
* Sort descending
|
||||
*
|
||||
* @param A query param - Could be a constant such as <code>Patient.ADDRESS</code> or a custom
|
||||
* @param theParam A query param - Could be a constant such as <code>Patient.ADDRESS</code> or a custom
|
||||
* param such as <code>new StringClientParam("foo")</code>
|
||||
*/
|
||||
IQuery<T> descending(IParam theParam);
|
||||
|
|
|
@ -187,12 +187,6 @@ public interface IServerInterceptor {
|
|||
* A bean containing details about the request that is about to be processed, including
|
||||
* @param theResponseObject
|
||||
* The actual object which is being streamed to the client as a response
|
||||
* @param theServletRequest
|
||||
* The incoming request
|
||||
* @param theServletResponse
|
||||
* The response. Note that interceptors may choose to provide a response (i.e. by calling
|
||||
* {@link HttpServletResponse#getWriter()}) but in that case it is important to return <code>false</code>
|
||||
* to indicate that the server itself should not also provide a response.
|
||||
* @return Return <code>true</code> if processing should continue normally. This is generally the right thing to do.
|
||||
* If your interceptor is providing a response rather than letting HAPI handle the response normally, you
|
||||
* must return <code>false</code>. In this case, no further processing will occur and no further interceptors
|
||||
|
@ -201,7 +195,7 @@ public interface IServerInterceptor {
|
|||
* This exception may be thrown to indicate that the interceptor has detected an unauthorized access
|
||||
* attempt. If thrown, processing will stop and an HTTP 401 will be returned to the client.
|
||||
*/
|
||||
boolean outgoingResponse(RequestDetails theRequest, Bundle bundle);
|
||||
boolean outgoingResponse(RequestDetails theRequest, Bundle theResponseObject);
|
||||
|
||||
/**
|
||||
* This method is called after the server implementation method has been called, but before any attempt to stream the
|
||||
|
|
|
@ -20,6 +20,16 @@ package ca.uhn.fhir.jpa.config;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.*;
|
||||
import ca.uhn.fhir.jpa.term.HapiTerminologySvcDstu2;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||
import ca.uhn.fhir.validation.IValidatorModule;
|
||||
import org.hl7.fhir.instance.hapi.validation.DefaultProfileValidationSupport;
|
||||
import org.hl7.fhir.instance.hapi.validation.FhirInstanceValidator;
|
||||
import org.hl7.fhir.instance.hapi.validation.ValidationSupportChain;
|
||||
import org.hl7.fhir.instance.validation.IResourceValidator.BestPracticeWarningLevel;
|
||||
import org.springframework.beans.factory.annotation.Autowire;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -27,17 +37,6 @@ import org.springframework.context.annotation.Lazy;
|
|||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||
import ca.uhn.fhir.jpa.dao.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParamExtractorDstu2;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParamRegistryDstu2;
|
||||
import ca.uhn.fhir.jpa.term.HapiTerminologySvcDstu2;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||
|
||||
@Configuration
|
||||
@EnableTransactionManagement
|
||||
public class BaseDstu2Config extends BaseConfig {
|
||||
|
@ -75,6 +74,15 @@ public class BaseDstu2Config extends BaseConfig {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Bean(name = "myInstanceValidatorDstu2")
|
||||
@Lazy
|
||||
public IValidatorModule instanceValidatorDstu2() {
|
||||
FhirInstanceValidator retVal = new FhirInstanceValidator();
|
||||
retVal.setBestPracticeWarningLevel(BestPracticeWarningLevel.Warning);
|
||||
retVal.setValidationSupport(new ValidationSupportChain(new DefaultProfileValidationSupport(), jpaValidationSupportDstu2()));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public IFulltextSearchSvc searchDao() {
|
||||
FulltextSearchSvcImpl searchDao = new FulltextSearchSvcImpl();
|
||||
|
|
|
@ -312,29 +312,14 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
}
|
||||
}
|
||||
|
||||
Set<String> treatReferencesAsLogical = myConfig.getTreatReferencesAsLogical();
|
||||
if (treatReferencesAsLogical != null) {
|
||||
boolean isLogical = false;
|
||||
for (String nextLogicalRef : treatReferencesAsLogical) {
|
||||
nextLogicalRef = trim(nextLogicalRef);
|
||||
if (nextLogicalRef.charAt(nextLogicalRef.length() - 1) == '*') {
|
||||
if (nextId.getValue().startsWith(nextLogicalRef.substring(0, nextLogicalRef.length() -1))) {
|
||||
isLogical = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (nextId.getValue().equals(nextLogicalRef)) {
|
||||
isLogical = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isLogical) {
|
||||
continue;
|
||||
if (isLogicalReference(nextId)) {
|
||||
ResourceLink resourceLink = new ResourceLink(nextPathAndRef.getPath(), theEntity, nextId, theUpdateTime);
|
||||
if (theLinks.add(resourceLink)) {
|
||||
ourLog.info("Indexing remote resource reference URL: {}", nextId);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
String baseUrl = nextId.getBaseUrl();
|
||||
String typeString = nextId.getResourceType();
|
||||
if (isBlank(typeString)) {
|
||||
|
@ -412,6 +397,26 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
|
||||
}
|
||||
|
||||
protected boolean isLogicalReference(IIdType theId) {
|
||||
Set<String> treatReferencesAsLogical = myConfig.getTreatReferencesAsLogical();
|
||||
if (treatReferencesAsLogical != null) {
|
||||
for (String nextLogicalRef : treatReferencesAsLogical) {
|
||||
nextLogicalRef = trim(nextLogicalRef);
|
||||
if (nextLogicalRef.charAt(nextLogicalRef.length() - 1) == '*') {
|
||||
if (theId.getValue().startsWith(nextLogicalRef.substring(0, nextLogicalRef.length() - 1))) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (theId.getValue().equals(nextLogicalRef)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Set<ResourceIndexedSearchParamCoords> extractSearchParamCoords(ResourceTable theEntity, IBaseResource theResource) {
|
||||
return mySearchParamExtractor.extractSearchParamCoords(theEntity, theResource);
|
||||
}
|
||||
|
@ -959,12 +964,11 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
* Subclasses may override to provide behaviour. Called when a resource has been inserted into the database for the first time.
|
||||
*
|
||||
* @param theEntity
|
||||
* The entity being updated (Do not modify the entity! Undefined behaviour will occur!)
|
||||
* The entity being updated (Do not modify the entity! Undefined behaviour will occur!)
|
||||
* @param theTag
|
||||
* The tag
|
||||
* The tag
|
||||
* @return Returns <code>true</code> if the tag should be removed
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
protected void postPersist(ResourceTable theEntity, T theResource) {
|
||||
// nothing
|
||||
}
|
||||
|
@ -973,9 +977,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
* Subclasses may override to provide behaviour. Called when a pre-existing resource has been updated in the database
|
||||
*
|
||||
* @param theEntity
|
||||
* The resource
|
||||
* The resource
|
||||
* @param theResource
|
||||
* The resource being persisted
|
||||
* The resource being persisted
|
||||
*/
|
||||
protected void postUpdate(ResourceTable theEntity, T theResource) {
|
||||
// nothing
|
||||
|
@ -998,7 +1002,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
return ids;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@CoverageIgnore
|
||||
public BaseHasResource readEntity(IIdType theValueId) {
|
||||
throw new NotImplementedException("");
|
||||
|
@ -1031,9 +1034,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
* </p>
|
||||
*
|
||||
* @param theEntity
|
||||
* The entity being updated (Do not modify the entity! Undefined behaviour will occur!)
|
||||
* The entity being updated (Do not modify the entity! Undefined behaviour will occur!)
|
||||
* @param theTag
|
||||
* The tag
|
||||
* The tag
|
||||
* @return Retturns <code>true</code> if the tag should be removed
|
||||
*/
|
||||
protected boolean shouldDroppedTagBeRemovedOnUpdate(ResourceTable theEntity, ResourceTag theTag) {
|
||||
|
@ -1269,7 +1272,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
setUpdatedTime(uriParams, theUpdateTime);
|
||||
setUpdatedTime(coordsParams, theUpdateTime);
|
||||
setUpdatedTime(tokenParams, theUpdateTime);
|
||||
|
||||
|
||||
/*
|
||||
* Handle references within the resource that are match URLs, for example references like "Patient?identifier=foo". These match URLs are resolved and replaced with the ID of the
|
||||
* matching
|
||||
|
@ -1531,11 +1534,14 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
|
||||
for (IBase nextChild : values) {
|
||||
IBaseReference nextRef = (IBaseReference) nextChild;
|
||||
if (!isBlank(nextRef.getReferenceElement().getResourceType())) {
|
||||
if (!nextRef.getReferenceElement().getValue().contains("?")) {
|
||||
if (!validTypes.contains(nextRef.getReferenceElement().getResourceType())) {
|
||||
throw new UnprocessableEntityException(
|
||||
"Invalid reference found at path '" + newPath + "'. Resource type '" + nextRef.getReferenceElement().getResourceType() + "' is not valid for this path");
|
||||
IIdType referencedId = nextRef.getReferenceElement();
|
||||
if (!isBlank(referencedId.getResourceType())) {
|
||||
if (!isLogicalReference(referencedId)) {
|
||||
if (!referencedId.getValue().contains("?")) {
|
||||
if (!validTypes.contains(referencedId.getResourceType())) {
|
||||
throw new UnprocessableEntityException(
|
||||
"Invalid reference found at path '" + newPath + "'. Resource type '" + referencedId.getResourceType() + "' is not valid for this path");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1575,9 +1581,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
* "subsetted" tag and rejects resources which have it. Subclasses should call the superclass implementation to preserve this check.
|
||||
*
|
||||
* @param theResource
|
||||
* The resource that is about to be persisted
|
||||
* The resource that is about to be persisted
|
||||
* @param theEntityToSave
|
||||
* TODO
|
||||
* TODO
|
||||
*/
|
||||
protected void validateResourceForStorage(T theResource, ResourceTable theEntityToSave) {
|
||||
Object tag = null;
|
||||
|
|
|
@ -56,7 +56,8 @@ public class DaoConfig {
|
|||
// ***
|
||||
// update setter javadoc if default changes
|
||||
// ***
|
||||
private boolean myAllowInlineMatchUrlReferences = false;
|
||||
private boolean myAllowInlineMatchUrlReferences = true;
|
||||
|
||||
private boolean myAllowMultipleDelete;
|
||||
private boolean myDefaultSearchParamsCanBeOverridden = false;
|
||||
// ***
|
||||
|
@ -93,6 +94,20 @@ public class DaoConfig {
|
|||
private Set<String> myTreatBaseUrlsAsLocal = new HashSet<String>();
|
||||
private Set<String> myTreatReferencesAsLogical = new HashSet<String>(DEFAULT_LOGICAL_BASE_URLS);
|
||||
|
||||
/**
|
||||
* Add a value to the {@link #setTreatReferencesAsLogical(Set) logical references list}.
|
||||
*
|
||||
* @see #setTreatReferencesAsLogical(Set)
|
||||
*/
|
||||
public void addTreatReferencesAsLogical(String theTreatReferencesAsLogical) {
|
||||
validateTreatBaseUrlsAsLocal(theTreatReferencesAsLogical);
|
||||
|
||||
if (myTreatReferencesAsLogical == null) {
|
||||
myTreatReferencesAsLogical = new HashSet<String>();
|
||||
}
|
||||
myTreatReferencesAsLogical.add(theTreatReferencesAsLogical);
|
||||
}
|
||||
|
||||
/**
|
||||
* When a code system is added that contains more than this number of codes,
|
||||
* the code system will be indexed later in an incremental process in order to
|
||||
|
@ -115,9 +130,9 @@ public class DaoConfig {
|
|||
* (next/prev links in search response bundles) will become invalid. Defaults to 1 hour.
|
||||
* </p>
|
||||
* <p>
|
||||
*
|
||||
* @see To disable this feature entirely, see {@link #setExpireSearchResults(boolean)}
|
||||
* </p>
|
||||
* <p>
|
||||
* To disable this feature entirely, see {@link #setExpireSearchResults(boolean)}
|
||||
* </p>
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
|
@ -196,9 +211,9 @@ public class DaoConfig {
|
|||
* references instead of being treated as real references.
|
||||
* <p>
|
||||
* A logical reference is a reference which is treated as an identifier, and
|
||||
* does not neccesarily resolve. See {@link http://hl7.org/fhir/references.html} for
|
||||
* does not neccesarily resolve. See {@link "http://hl7.org/fhir/references.html"} for
|
||||
* a description of logical references. For example, the valueset
|
||||
* {@link http://hl7.org/fhir/valueset-quantity-comparator.html} is a logical
|
||||
* {@link "http://hl7.org/fhir/valueset-quantity-comparator.html"} is a logical
|
||||
* reference.
|
||||
* </p>
|
||||
* <p>
|
||||
|
@ -209,7 +224,7 @@ public class DaoConfig {
|
|||
* <li><code>http://example.com/some-base*</code> <b>(will match anything beginning with the part before the *)</b></li>
|
||||
* </ul>
|
||||
*
|
||||
* @see #DEFAULT_LOGICAL_BASE_URLS for a list of default values for this setting
|
||||
* @see #DEFAULT_LOGICAL_BASE_URLS Default values for this property
|
||||
*/
|
||||
public Set<String> getTreatReferencesAsLogical() {
|
||||
return myTreatReferencesAsLogical;
|
||||
|
@ -337,7 +352,9 @@ public class DaoConfig {
|
|||
* to "Patient?identifier=12345", this is reference match URL will be resolved and replaced according
|
||||
* to the usual match URL rules.
|
||||
* <p>
|
||||
* Default is false for now, as this is an experimental feature.
|
||||
* Default is {@literal true} beginning in HAPI FHIR 2.4, since this
|
||||
* feature is now specified in the FHIR specification. (Previously it
|
||||
* was an experimental/rpposed feature)
|
||||
* </p>
|
||||
*
|
||||
* @since 1.5
|
||||
|
@ -401,8 +418,10 @@ public class DaoConfig {
|
|||
* </p>
|
||||
* <p>
|
||||
*
|
||||
* @see To disable this feature entirely, see {@link #setExpireSearchResults(boolean)}
|
||||
* </p>
|
||||
* <p>
|
||||
* To disable this feature entirely, see {@link #setExpireSearchResults(boolean)}
|
||||
* </p>
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public void setExpireSearchResultsAfterMillis(long theExpireSearchResultsAfterMillis) {
|
||||
|
@ -418,7 +437,7 @@ public class DaoConfig {
|
|||
* paging provider instead. Deprecated in HAPI FHIR 2.3 (Jan 2017)
|
||||
*/
|
||||
@Deprecated
|
||||
public void setHardSearchLimit(@SuppressWarnings("unused") int theHardSearchLimit) {
|
||||
public void setHardSearchLimit(int theHardSearchLimit) {
|
||||
// this method does nothing
|
||||
}
|
||||
|
||||
|
@ -528,6 +547,12 @@ public class DaoConfig {
|
|||
* means no references will be treated as external
|
||||
*/
|
||||
public void setTreatBaseUrlsAsLocal(Set<String> theTreatBaseUrlsAsLocal) {
|
||||
if (theTreatBaseUrlsAsLocal != null) {
|
||||
for (String next : theTreatBaseUrlsAsLocal) {
|
||||
validateTreatBaseUrlsAsLocal(next);
|
||||
}
|
||||
}
|
||||
|
||||
HashSet<String> treatBaseUrlsAsLocal = new HashSet<String>();
|
||||
for (String next : ObjectUtils.defaultIfNull(theTreatBaseUrlsAsLocal, new HashSet<String>())) {
|
||||
while (next.endsWith("/")) {
|
||||
|
@ -544,9 +569,9 @@ public class DaoConfig {
|
|||
* references instead of being treated as real references.
|
||||
* <p>
|
||||
* A logical reference is a reference which is treated as an identifier, and
|
||||
* does not neccesarily resolve. See {@link http://hl7.org/fhir/references.html} for
|
||||
* does not neccesarily resolve. See {@link "http://hl7.org/fhir/references.html"} for
|
||||
* a description of logical references. For example, the valueset
|
||||
* {@link http://hl7.org/fhir/valueset-quantity-comparator.html} is a logical
|
||||
* {@link "http://hl7.org/fhir/valueset-quantity-comparator.html"} is a logical
|
||||
* reference.
|
||||
* </p>
|
||||
* <p>
|
||||
|
@ -557,11 +582,23 @@ public class DaoConfig {
|
|||
* <li><code>http://example.com/some-base*</code> <b>(will match anything beginning with the part before the *)</b></li>
|
||||
* </ul>
|
||||
*
|
||||
* @see #DEFAULT_LOGICAL_BASE_URLS for a list of default values for this setting
|
||||
* @see #DEFAULT_LOGICAL_BASE_URLS Default values for this property
|
||||
*/
|
||||
public DaoConfig setTreatReferencesAsLogical(Set<String> theTreatReferencesAsLogical) {
|
||||
myTreatReferencesAsLogical = theTreatReferencesAsLogical;
|
||||
return this;
|
||||
}
|
||||
|
||||
private static void validateTreatBaseUrlsAsLocal(String theUrl) {
|
||||
Validate.notBlank(theUrl, "Base URL must not be null or empty");
|
||||
|
||||
int starIdx = theUrl.indexOf('*');
|
||||
if (starIdx != -1) {
|
||||
if (starIdx != theUrl.length() - 1) {
|
||||
throw new IllegalArgumentException("Base URL wildcard character (*) can only appear at the end of the string: " + theUrl);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,43 +1,5 @@
|
|||
package ca.uhn.fhir.jpa.dao;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2017 University Health Network
|
||||
* %%
|
||||
* 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 java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.instance.hapi.validation.DefaultProfileValidationSupport;
|
||||
import org.hl7.fhir.instance.hapi.validation.FhirInstanceValidator;
|
||||
import org.hl7.fhir.instance.hapi.validation.IValidationSupport;
|
||||
import org.hl7.fhir.instance.hapi.validation.ValidationSupportChain;
|
||||
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.validation.IResourceValidator.BestPracticeWarningLevel;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||
|
@ -64,6 +26,38 @@ import ca.uhn.fhir.validation.FhirValidator;
|
|||
import ca.uhn.fhir.validation.IValidationContext;
|
||||
import ca.uhn.fhir.validation.IValidatorModule;
|
||||
import ca.uhn.fhir.validation.ValidationResult;
|
||||
import org.hl7.fhir.instance.hapi.validation.IValidationSupport;
|
||||
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2017 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
public class FhirResourceDaoDstu2<T extends IResource> extends BaseHapiFhirResourceDao<T> {
|
||||
|
||||
|
@ -71,6 +65,9 @@ public class FhirResourceDaoDstu2<T extends IResource> extends BaseHapiFhirResou
|
|||
@Qualifier("myJpaValidationSupportDstu2")
|
||||
private IValidationSupport myJpaValidationSupport;
|
||||
|
||||
@Autowired()
|
||||
@Qualifier("myInstanceValidatorDstu2")
|
||||
private IValidatorModule myInstanceValidator;
|
||||
|
||||
@Override
|
||||
protected List<Object> getIncludeValues(FhirTerser theTerser, Include theInclude, IBaseResource theResource, RuntimeResourceDefinition theResourceDef) {
|
||||
|
@ -124,10 +121,7 @@ public class FhirResourceDaoDstu2<T extends IResource> extends BaseHapiFhirResou
|
|||
|
||||
FhirValidator validator = getContext().newValidator();
|
||||
|
||||
FhirInstanceValidator val = new FhirInstanceValidator();
|
||||
val.setBestPracticeWarningLevel(BestPracticeWarningLevel.Warning);
|
||||
val.setValidationSupport(new ValidationSupportChain(new DefaultProfileValidationSupport(), myJpaValidationSupport));
|
||||
validator.registerValidatorModule(val);
|
||||
validator.registerValidatorModule(myInstanceValidator);
|
||||
|
||||
validator.registerValidatorModule(new IdChecker(theMode));
|
||||
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
package ca.uhn.fhir.jpa.config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Properties;
|
||||
|
||||
@Configuration
|
||||
@EnableTransactionManagement()
|
||||
|
@ -65,4 +64,19 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
|
|||
return extraProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean which validates incoming requests
|
||||
*/
|
||||
@Bean
|
||||
@Lazy
|
||||
public RequestValidatingInterceptor requestValidatingInterceptor() {
|
||||
RequestValidatingInterceptor requestValidator = new RequestValidatingInterceptor();
|
||||
requestValidator.setFailOnSeverity(ResultSeverityEnum.ERROR);
|
||||
requestValidator.setAddResponseHeaderOnSeverity(null);
|
||||
requestValidator.setAddResponseOutcomeHeaderOnSeverity(ResultSeverityEnum.INFORMATION);
|
||||
requestValidator.addValidatorModule(instanceValidatorDstu2());
|
||||
|
||||
return requestValidator;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package ca.uhn.fhir.jpa.dao;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class DaoConfigTest {
|
||||
|
||||
@Test
|
||||
public void testValidLogicalPattern() {
|
||||
new DaoConfig().setTreatBaseUrlsAsLocal(new HashSet<String>(Arrays.asList("http://foo")));
|
||||
new DaoConfig().setTreatBaseUrlsAsLocal(new HashSet<String>(Arrays.asList("http://foo*")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidLogicalPattern() {
|
||||
try {
|
||||
new DaoConfig().setTreatBaseUrlsAsLocal(new HashSet<String>(Arrays.asList("http://*foo")));
|
||||
fail();
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertEquals("Base URL wildcard character (*) can only appear at the end of the string: http://*foo", e.getMessage());
|
||||
}
|
||||
try {
|
||||
new DaoConfig().setTreatBaseUrlsAsLocal(new HashSet<String>(Arrays.asList("http://foo**")));
|
||||
fail();
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertEquals("Base URL wildcard character (*) can only appear at the end of the string: http://foo**", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -65,28 +65,12 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu2Test.class);
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
@After
|
||||
public final void after() {
|
||||
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());
|
||||
myDaoConfig.setTreatReferencesAsLogical(new DaoConfig().getTreatReferencesAsLogical());
|
||||
}
|
||||
|
||||
/**
|
||||
* See #534
|
||||
*/
|
||||
@Test
|
||||
public void testBuiltInLogicalReferences() throws IOException {
|
||||
myDaoConfig.getTreatReferencesAsLogical().add("http://phr.kanta.fi/fiphr-vs-*");
|
||||
|
||||
ValueSet vsBodySite = loadResourceFromClasspath(ValueSet.class, "/issue534/fiphr-vs-bodysite.xml");
|
||||
myValueSetDao.create(vsBodySite, mySrd);
|
||||
ValueSet vsObsMethod = loadResourceFromClasspath(ValueSet.class, "/issue534/fiphr-vs-observationmethod.xml");
|
||||
myValueSetDao.create(vsObsMethod, mySrd);
|
||||
|
||||
StructureDefinition sd = loadResourceFromClasspath(StructureDefinition.class, "/issue534/bw_profile_snapshot.xml");
|
||||
myStructureDefinitionDao.create(sd, mySrd);
|
||||
}
|
||||
|
||||
|
||||
private void assertGone(IIdType theId) {
|
||||
try {
|
||||
assertNotGone(theId);
|
||||
|
@ -96,82 +80,13 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
}
|
||||
}
|
||||
|
||||
@After
|
||||
public final void after() {
|
||||
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());
|
||||
myDaoConfig.setTreatReferencesAsLogical(new DaoConfig().getTreatReferencesAsLogical());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testValidateAgainstDstu2Profile() throws Exception {
|
||||
myDaoConfig.setAllowExternalReferences(true);
|
||||
|
||||
String stream = IOUtils.toString(getClass().getResourceAsStream("/binu_testpatient_structuredefinition_dstu2.xml"), StandardCharsets.UTF_8);
|
||||
|
||||
StructureDefinition sd = myFhirCtx.newXmlParser().parseResource(StructureDefinition.class, stream);
|
||||
myStructureDefinitionDao.create(sd, mySrd);
|
||||
|
||||
String rawResource = IOUtils.toString(getClass().getResourceAsStream("/binu_testpatient_resource.json"), StandardCharsets.UTF_8);
|
||||
try {
|
||||
myValueSetDao.validate(null, null, rawResource, EncodingEnum.JSON, ValidationModeEnum.UPDATE, null, mySrd);
|
||||
fail();
|
||||
} catch (PreconditionFailedException e) {
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(e.getOperationOutcome()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreateBundleAllowsDocumentAndCollection() {
|
||||
String methodName = "testCreateBundleAllowsDocumentAndCollection";
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
||||
IIdType pid = myPatientDao.create(p, mySrd).getId();
|
||||
p.setId(pid);
|
||||
ourLog.info("Created patient, got it: {}", pid);
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.setType((BundleTypeEnum)null);
|
||||
bundle.addEntry().setResource(p).setFullUrl(pid.toUnqualifiedVersionless().getValue());
|
||||
try {
|
||||
myBundleDao.create(bundle, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("Unable to store a Bundle resource on this server with a Bundle.type of: (missing)", e.getMessage());
|
||||
}
|
||||
|
||||
bundle = new Bundle();
|
||||
bundle.setType(BundleTypeEnum.BATCH_RESPONSE);
|
||||
bundle.addEntry().setResource(p).setFullUrl(pid.toUnqualifiedVersionless().getValue());
|
||||
try {
|
||||
myBundleDao.create(bundle, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("Unable to store a Bundle resource on this server with a Bundle.type of: batch-response", e.getMessage());
|
||||
}
|
||||
|
||||
bundle = new Bundle();
|
||||
bundle.setType(BundleTypeEnum.COLLECTION);
|
||||
bundle.addEntry().setResource(p).setFullUrl(pid.toUnqualifiedVersionless().getValue());
|
||||
myBundleDao.create(bundle, mySrd);
|
||||
|
||||
bundle = new Bundle();
|
||||
bundle.setType(BundleTypeEnum.DOCUMENT);
|
||||
bundle.addEntry().setResource(p).setFullUrl(pid.toUnqualifiedVersionless().getValue());
|
||||
myBundleDao.create(bundle, mySrd);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This gets called from assertGone too! Careful about exceptions...
|
||||
*/
|
||||
private void assertNotGone(IIdType theId) {
|
||||
if ("Patient".equals(theId.getResourceType())) {
|
||||
myPatientDao.read(theId, mySrd);
|
||||
} else if ("Organization".equals(theId.getResourceType())){
|
||||
} else if ("Organization".equals(theId.getResourceType())) {
|
||||
myOrganizationDao.read(theId, mySrd);
|
||||
} else {
|
||||
fail("No type");
|
||||
|
@ -188,7 +103,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
}
|
||||
|
||||
private String log(IBundleProvider theHistory) {
|
||||
StringBuilder b =new StringBuilder(theHistory.size() + " results: ");
|
||||
StringBuilder b = new StringBuilder(theHistory.size() + " results: ");
|
||||
for (IBaseResource next : theHistory.getResources(0, theHistory.size())) {
|
||||
b.append("\n ").append(next.getIdElement().toUnqualified().getValue());
|
||||
}
|
||||
|
@ -233,6 +148,23 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* See #534
|
||||
*/
|
||||
@Test
|
||||
public void testBuiltInLogicalReferences() throws IOException {
|
||||
myDaoConfig.getTreatReferencesAsLogical().add("http://phr.kanta.fi/fiphr-vs-*");
|
||||
|
||||
ValueSet vsBodySite = loadResourceFromClasspath(ValueSet.class, "/issue534/fiphr-vs-bodysite.xml");
|
||||
myValueSetDao.create(vsBodySite, mySrd);
|
||||
ValueSet vsObsMethod = loadResourceFromClasspath(ValueSet.class, "/issue534/fiphr-vs-observationmethod.xml");
|
||||
myValueSetDao.create(vsObsMethod, mySrd);
|
||||
|
||||
// Just make sure this saves
|
||||
StructureDefinition sd = loadResourceFromClasspath(StructureDefinition.class, "/issue534/bw_profile_snapshot.xml");
|
||||
myStructureDefinitionDao.create(sd, mySrd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCantSearchForDeletedResourceByLanguageOrTag() {
|
||||
String methodName = "testCantSearchForDeletedResourceByLanguageOrTag";
|
||||
|
@ -384,6 +316,48 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateBundleAllowsDocumentAndCollection() {
|
||||
String methodName = "testCreateBundleAllowsDocumentAndCollection";
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
||||
IIdType pid = myPatientDao.create(p, mySrd).getId();
|
||||
p.setId(pid);
|
||||
ourLog.info("Created patient, got it: {}", pid);
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.setType((BundleTypeEnum) null);
|
||||
bundle.addEntry().setResource(p).setFullUrl(pid.toUnqualifiedVersionless().getValue());
|
||||
try {
|
||||
myBundleDao.create(bundle, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("Unable to store a Bundle resource on this server with a Bundle.type of: (missing)", e.getMessage());
|
||||
}
|
||||
|
||||
bundle = new Bundle();
|
||||
bundle.setType(BundleTypeEnum.BATCH_RESPONSE);
|
||||
bundle.addEntry().setResource(p).setFullUrl(pid.toUnqualifiedVersionless().getValue());
|
||||
try {
|
||||
myBundleDao.create(bundle, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("Unable to store a Bundle resource on this server with a Bundle.type of: batch-response", e.getMessage());
|
||||
}
|
||||
|
||||
bundle = new Bundle();
|
||||
bundle.setType(BundleTypeEnum.COLLECTION);
|
||||
bundle.addEntry().setResource(p).setFullUrl(pid.toUnqualifiedVersionless().getValue());
|
||||
myBundleDao.create(bundle, mySrd);
|
||||
|
||||
bundle = new Bundle();
|
||||
bundle.setType(BundleTypeEnum.DOCUMENT);
|
||||
bundle.addEntry().setResource(p).setFullUrl(pid.toUnqualifiedVersionless().getValue());
|
||||
myBundleDao.create(bundle, mySrd);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateOperationOutcome() {
|
||||
/*
|
||||
|
@ -818,8 +792,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
assertThat(found, empty());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testDeleteResource() {
|
||||
int initialHistory = myPatientDao.history(null, null, mySrd).size();
|
||||
|
@ -882,7 +855,6 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
assertEquals(0, patients.size());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDeleteThenUndelete() {
|
||||
|
@ -917,7 +889,6 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
assertEquals(id2, gotId);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDeleteWithMatchUrl() {
|
||||
String methodName = "testDeleteWithMatchUrl";
|
||||
|
@ -974,23 +945,24 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
myPatientDao.deleteByUrl("Patient?organization.identifier=http://example.com|" + methodName, mySrd);
|
||||
assertGone(id);
|
||||
assertNotGone(orgId);
|
||||
|
||||
|
||||
myOrganizationDao.deleteByUrl("Organization?identifier=http://example.com|" + methodName, mySrd);
|
||||
assertGone(id);
|
||||
assertGone(orgId);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteWithMatchUrlChainedProfile() {
|
||||
String methodName = "testDeleteWithMatchUrlChainedProfile";
|
||||
|
||||
List<IdDt> profileList = new ArrayList<IdDt>();
|
||||
profileList.add(new IdDt("http://foo"));
|
||||
|
||||
|
||||
Organization org = new Organization();
|
||||
ResourceMetadataKeyEnum.PROFILES.put(org, profileList);
|
||||
org.setName(methodName);
|
||||
|
||||
|
||||
IIdType orgId = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient p = new Patient();
|
||||
|
@ -1002,7 +974,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
|
||||
myPatientDao.deleteByUrl("Patient?organization._profile=http://foo", mySrd);
|
||||
assertGone(id);
|
||||
|
||||
|
||||
myOrganizationDao.deleteByUrl("Organization?_profile=http://foo", mySrd);
|
||||
try {
|
||||
myOrganizationDao.read(orgId, mySrd);
|
||||
|
@ -1027,8 +999,6 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testDeleteWithMatchUrlChainedString() {
|
||||
String methodName = "testDeleteWithMatchUrlChainedString";
|
||||
|
@ -1055,11 +1025,11 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
|
||||
TagList tl = new TagList();
|
||||
tl.addTag("http://foo", "term");
|
||||
|
||||
|
||||
Organization org = new Organization();
|
||||
ResourceMetadataKeyEnum.TAG_LIST.put(org, tl);
|
||||
org.setName(methodName);
|
||||
|
||||
|
||||
IIdType orgId = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient p = new Patient();
|
||||
|
@ -1071,7 +1041,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
|
||||
myPatientDao.deleteByUrl("Patient?organization._tag=http://foo|term", mySrd);
|
||||
assertGone(id);
|
||||
|
||||
|
||||
myOrganizationDao.deleteByUrl("Organization?_tag=http://foo|term", mySrd);
|
||||
try {
|
||||
myOrganizationDao.read(orgId, mySrd);
|
||||
|
@ -1116,9 +1086,9 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
/*
|
||||
* Org 2 has a name
|
||||
*/
|
||||
|
||||
|
||||
Organization org2 = new Organization();
|
||||
org2.setName(methodName);
|
||||
org2.setName(methodName);
|
||||
org2.addIdentifier().setValue(methodName);
|
||||
IIdType org2Id = myOrganizationDao.create(org2, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
|
@ -1131,13 +1101,13 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
ourLog.info("Org ID 1 : {}", org1Id);
|
||||
ourLog.info("Pat ID 2 : {}", patId2);
|
||||
ourLog.info("Org ID 2 : {}", org2Id);
|
||||
|
||||
|
||||
myPatientDao.deleteByUrl("Patient?organization.name:missing=true", mySrd);
|
||||
assertGone(patId1);
|
||||
assertNotGone(patId2);
|
||||
assertNotGone(org1Id);
|
||||
assertNotGone(org2Id);
|
||||
|
||||
|
||||
myOrganizationDao.deleteByUrl("Organization?name:missing=true", mySrd);
|
||||
assertGone(patId1);
|
||||
assertNotGone(patId2);
|
||||
|
@ -1149,7 +1119,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
assertGone(patId2);
|
||||
assertGone(org1Id);
|
||||
assertNotGone(org2Id);
|
||||
|
||||
|
||||
myOrganizationDao.deleteByUrl("Organization?name:missing=false", mySrd);
|
||||
assertGone(patId1);
|
||||
assertGone(patId2);
|
||||
|
@ -1186,13 +1156,13 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
String methodName = "testHistoryOverMultiplePages";
|
||||
|
||||
/*
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
Patient patient = new Patient();
|
||||
patient.addName().addFamily(methodName + "__" + i);
|
||||
myPatientDao.create(patient).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
*/
|
||||
|
||||
* for (int i = 0; i < 1000; i++) {
|
||||
* Patient patient = new Patient();
|
||||
* patient.addName().addFamily(methodName + "__" + i);
|
||||
* myPatientDao.create(patient).getId().toUnqualifiedVersionless();
|
||||
* }
|
||||
*/
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().addFamily(methodName);
|
||||
IIdType id = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
@ -2976,4 +2946,27 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateAgainstDstu2Profile() throws Exception {
|
||||
myDaoConfig.setAllowExternalReferences(true);
|
||||
|
||||
String stream = IOUtils.toString(getClass().getResourceAsStream("/binu_testpatient_structuredefinition_dstu2.xml"), StandardCharsets.UTF_8);
|
||||
|
||||
StructureDefinition sd = myFhirCtx.newXmlParser().parseResource(StructureDefinition.class, stream);
|
||||
myStructureDefinitionDao.create(sd, mySrd);
|
||||
|
||||
String rawResource = IOUtils.toString(getClass().getResourceAsStream("/binu_testpatient_resource.json"), StandardCharsets.UTF_8);
|
||||
try {
|
||||
myValueSetDao.validate(null, null, rawResource, EncodingEnum.JSON, ValidationModeEnum.UPDATE, null, mySrd);
|
||||
fail();
|
||||
} catch (PreconditionFailedException e) {
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(e.getOperationOutcome()));
|
||||
}
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import static org.mockito.Mockito.reset;
|
|||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
@ -82,6 +83,7 @@ import org.hl7.fhir.dstu3.model.UriType;
|
|||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
@ -89,10 +91,7 @@ import org.mockito.ArgumentCaptor;
|
|||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
|
||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.dao.*;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.entity.TagTypeEnum;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
|
@ -129,6 +128,12 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3Test.class);
|
||||
|
||||
@After
|
||||
public final void after() {
|
||||
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());
|
||||
myDaoConfig.setTreatReferencesAsLogical(new DaoConfig().getTreatReferencesAsLogical());
|
||||
}
|
||||
|
||||
private void assertGone(IIdType theId) {
|
||||
try {
|
||||
assertNotGone(theId);
|
||||
|
@ -152,7 +157,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
fail("Can't handle type: " + theId.getResourceType());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private List<String> extractNames(IBundleProvider theSearch) {
|
||||
ArrayList<String> retVal = new ArrayList<String>();
|
||||
for (IBaseResource next : theSearch.getResources(0, theSearch.size())) {
|
||||
|
@ -167,7 +172,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
retVal.addCoding().setSystem(theSystem).setCode(theCode);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
private void sort(ArrayList<Coding> thePublished) {
|
||||
ArrayList<Coding> tags = new ArrayList<Coding>(thePublished);
|
||||
Collections.sort(tags, new Comparator<Coding>() {
|
||||
|
@ -194,7 +199,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private List<UriType> sortIds(List<UriType> theProfiles) {
|
||||
ArrayList<UriType> retVal = new ArrayList<UriType>(theProfiles);
|
||||
Collections.sort(retVal, new Comparator<UriType>() {
|
||||
|
@ -288,21 +293,21 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
Encounter enc = new Encounter();
|
||||
enc.getPeriod().setStartElement(new DateTimeType("2016-05-10")).setEndElement(new DateTimeType("2016-05-20"));
|
||||
String id = myEncounterDao.create(enc, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
|
||||
List<String> ids;
|
||||
|
||||
|
||||
/*
|
||||
* This should not match, per the definition of eq
|
||||
*/
|
||||
|
||||
|
||||
ids = toUnqualifiedVersionlessIdValues(myEncounterDao.search(Encounter.SP_DATE, new DateParam("2016-05-15")));
|
||||
assertThat(ids, empty());
|
||||
|
||||
ids = toUnqualifiedVersionlessIdValues(myEncounterDao.search(Encounter.SP_DATE, new DateParam("eq2016-05-15")));
|
||||
assertThat(ids, empty());
|
||||
|
||||
|
||||
// Should match
|
||||
|
||||
|
||||
ids = toUnqualifiedVersionlessIdValues(myEncounterDao.search(Encounter.SP_DATE, new DateParam("eq2016")));
|
||||
assertThat(ids, contains(id));
|
||||
|
||||
|
@ -468,9 +473,9 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
CodeSystem cs = new CodeSystem();
|
||||
cs.setStatus(PublicationStatus.DRAFT);
|
||||
IIdType id = myCodeSystemDao.create(cs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
|
||||
myCodeSystemDao.delete(id, mySrd);
|
||||
|
||||
|
||||
assertGone(id.toUnqualifiedVersionless());
|
||||
}
|
||||
|
||||
|
@ -544,7 +549,6 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreateDifferentTypesWithSameForcedId() {
|
||||
String idName = "forcedId";
|
||||
|
@ -1047,7 +1051,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
|
||||
@Test
|
||||
public void testDeleteResource() {
|
||||
int initialHistory = myPatientDao.history((Date)null, null, mySrd).size();
|
||||
int initialHistory = myPatientDao.history((Date) null, null, mySrd).size();
|
||||
|
||||
IIdType id1;
|
||||
IIdType id2;
|
||||
|
@ -1089,7 +1093,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
// good
|
||||
}
|
||||
|
||||
IBundleProvider history = myPatientDao.history((Date)null, null, mySrd);
|
||||
IBundleProvider history = myPatientDao.history((Date) null, null, mySrd);
|
||||
assertEquals(4 + initialHistory, history.size());
|
||||
List<IBaseResource> resources = history.getResources(0, 4);
|
||||
assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get((IAnyResource) resources.get(0)));
|
||||
|
@ -1146,7 +1150,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
Observation obs1 = new Observation();
|
||||
obs1.setStatus(ObservationStatus.FINAL);
|
||||
IIdType obs1id = myObservationDao.create(obs1).getId().toUnqualifiedVersionless();
|
||||
|
||||
|
||||
Observation obs2 = new Observation();
|
||||
obs2.setStatus(ObservationStatus.FINAL);
|
||||
IIdType obs2id = myObservationDao.create(obs2).getId().toUnqualifiedVersionless();
|
||||
|
@ -1155,19 +1159,19 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
rpt.addIdentifier().setSystem("foo").setValue("IDENTIFIER");
|
||||
rpt.addResult(new Reference(obs2id));
|
||||
myDiagnosticReportDao.create(rpt).getId().toUnqualifiedVersionless();
|
||||
|
||||
|
||||
myObservationDao.read(obs1id);
|
||||
myObservationDao.read(obs2id);
|
||||
|
||||
|
||||
try {
|
||||
myObservationDao.deleteByUrl("Observation?_has:DiagnosticReport:result:identifier=foo|IDENTIFIER", mySrd);
|
||||
fail();
|
||||
} catch (ResourceVersionConflictException e) {
|
||||
assertConflictException(e);
|
||||
}
|
||||
|
||||
|
||||
myObservationDao.read(obs1id);
|
||||
myObservationDao.read(obs2id);
|
||||
myObservationDao.read(obs2id);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1461,7 +1465,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
}
|
||||
|
||||
// By type
|
||||
history = myPatientDao.history((Date)null, null, mySrd);
|
||||
history = myPatientDao.history((Date) null, null, mySrd);
|
||||
assertEquals(fullSize + 1, history.size());
|
||||
for (int i = 0; i < fullSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
|
@ -1528,7 +1532,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
}
|
||||
|
||||
// By type
|
||||
history = myPatientDao.history((Date)null, null, mySrd);
|
||||
history = myPatientDao.history((Date) null, null, mySrd);
|
||||
assertEquals(fullSize + 1, history.size());
|
||||
for (int i = 0; i < fullSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
|
@ -1585,7 +1589,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
inPatient.getMeta().addProfile("http://example.com/1");
|
||||
IIdType id = myPatientDao.create(inPatient, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
IBundleProvider history = myPatientDao.history((Date)null, null, mySrd);
|
||||
IBundleProvider history = myPatientDao.history((Date) null, null, mySrd);
|
||||
assertEquals(1, history.size());
|
||||
Patient outPatient = (Patient) history.getResources(0, 1).get(0);
|
||||
assertEquals("version1", inPatient.getName().get(0).getFamily());
|
||||
|
@ -1599,7 +1603,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
inPatient.getMeta().addProfile("http://example.com/2");
|
||||
myPatientDao.metaAddOperation(id, inPatient.getMeta(), mySrd);
|
||||
|
||||
history = myPatientDao.history((Date)null, null, mySrd);
|
||||
history = myPatientDao.history((Date) null, null, mySrd);
|
||||
assertEquals(1, history.size());
|
||||
outPatient = (Patient) history.getResources(0, 1).get(0);
|
||||
assertEquals("version1", inPatient.getName().get(0).getFamily());
|
||||
|
@ -1615,7 +1619,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
inPatient.getName().get(0).setFamily("version2");
|
||||
myPatientDao.update(inPatient, mySrd);
|
||||
|
||||
history = myPatientDao.history((Date)null, null, mySrd);
|
||||
history = myPatientDao.history((Date) null, null, mySrd);
|
||||
assertEquals(2, history.size());
|
||||
outPatient = (Patient) history.getResources(0, 2).get(0);
|
||||
assertEquals("version2", outPatient.getName().get(0).getFamily());
|
||||
|
@ -1682,13 +1686,13 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
}
|
||||
|
||||
List<String> idValues;
|
||||
|
||||
|
||||
idValues = toUnqualifiedIdValues(myPatientDao.history(id, preDates.get(0), preDates.get(3), mySrd));
|
||||
assertThat(idValues, contains(ids.get(2), ids.get(1), ids.get(0)));
|
||||
|
||||
|
||||
idValues = toUnqualifiedIdValues(myPatientDao.history(preDates.get(0), preDates.get(3), mySrd));
|
||||
assertThat(idValues, contains(ids.get(2), ids.get(1), ids.get(0)));
|
||||
|
||||
|
||||
idValues = toUnqualifiedIdValues(mySystemDao.history(preDates.get(0), preDates.get(3), mySrd));
|
||||
assertThat(idValues, contains(ids.get(2), ids.get(1), ids.get(0)));
|
||||
}
|
||||
|
@ -1709,7 +1713,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
|
||||
// No since
|
||||
|
||||
IBundleProvider history = myPatientDao.history((Date)null, null, mySrd);
|
||||
IBundleProvider history = myPatientDao.history((Date) null, null, mySrd);
|
||||
assertEquals(1, history.size());
|
||||
Patient outPatient = (Patient) history.getResources(0, 1).get(0);
|
||||
assertEquals("version1", inPatient.getName().get(0).getFamily());
|
||||
|
@ -1731,7 +1735,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
assertEquals(0, history.size());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testHistoryWithInvalidId() throws Exception {
|
||||
try {
|
||||
|
@ -1815,11 +1819,11 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
@Test
|
||||
public void testIndexConditionWithAllOnsetTypes() {
|
||||
// DateTimeType.class, Age.class, Period.class, Range.class, StringType.class
|
||||
|
||||
|
||||
Condition c0 = new Condition();
|
||||
c0.setOnset(new DateTimeType("2011-01-01"));
|
||||
myConditionDao.create(c0, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
|
||||
Condition c1 = new Condition();
|
||||
c1.setOnset(new Age().setValue(100L).setCode("AGECODE"));
|
||||
myConditionDao.create(c1, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
@ -1835,7 +1839,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
Condition c4 = new Condition();
|
||||
c4.setOnset(new StringType("FOO"));
|
||||
myConditionDao.create(c4, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstanceMetaOperations() {
|
||||
|
@ -2011,6 +2015,27 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See #534
|
||||
*/
|
||||
@Test
|
||||
public void testLogicalReferencesAreSearchable() throws IOException {
|
||||
myDaoConfig.setTreatReferencesAsLogical(null);
|
||||
myDaoConfig.addTreatReferencesAsLogical("http://foo.com/identifier*");
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.getManagingOrganization().setReference("http://foo.com/identifier/1");
|
||||
String p1id = myPatientDao.create(p1, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
Patient p2 = new Patient();
|
||||
p2.getManagingOrganization().setReference("http://foo.com/identifier/2");
|
||||
String p2id = myPatientDao.create(p2, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
IBundleProvider found = myPatientDao.search(Patient.SP_ORGANIZATION, new ReferenceParam("http://foo.com/identifier/1"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(found), contains(p1id));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(found), not(contains(p2id)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrganizationName() {
|
||||
|
||||
|
@ -3297,7 +3322,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
Date before = new DateTimeType("2011-01-01T10:00:00Z").getValue();
|
||||
Date middle = new DateTimeType("2011-01-02T10:00:00Z").getValue();
|
||||
Date after = new DateTimeType("2011-01-03T10:00:00Z").getValue();
|
||||
|
||||
|
||||
CarePlan cp = new CarePlan();
|
||||
cp.addActivity().getDetail().setScheduled(new Timing().addEvent(before).addEvent(middle).addEvent(after));
|
||||
cp.addActivity().getDetail();
|
||||
|
@ -3307,9 +3332,9 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
cp2.addActivity().getDetail().setScheduled(new StringType("FOO"));
|
||||
cp2.addActivity().getDetail();
|
||||
myCarePlanDao.create(cp2, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
|
||||
SearchParameterMap params;
|
||||
|
||||
|
||||
params = new SearchParameterMap();
|
||||
params.add(CarePlan.SP_ACTIVITY_DATE, new DateRangeParam("2010-01-01T10:00:00Z", null));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myCarePlanDao.search(params)), contains(id.getValue()));
|
||||
|
@ -3317,7 +3342,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
params = new SearchParameterMap();
|
||||
params.add(CarePlan.SP_ACTIVITY_DATE, new DateRangeParam("2011-01-01T10:00:00Z", null));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myCarePlanDao.search(params)), contains(id.getValue()));
|
||||
|
||||
|
||||
params = new SearchParameterMap();
|
||||
params.add(CarePlan.SP_ACTIVITY_DATE, new DateRangeParam("2012-01-01T10:00:00Z", null));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myCarePlanDao.search(params)), empty());
|
||||
|
@ -3364,7 +3389,8 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
}
|
||||
|
||||
public static void assertConflictException(ResourceVersionConflictException e) {
|
||||
assertThat(e.getMessage(), matchesPattern("Unable to delete [a-zA-Z]+/[0-9]+ because at least one resource has a reference to this resource. First reference found was resource [a-zA-Z]+/[0-9]+ in path [a-zA-Z]+.[a-zA-Z]+"));
|
||||
assertThat(e.getMessage(), matchesPattern(
|
||||
"Unable to delete [a-zA-Z]+/[0-9]+ because at least one resource has a reference to this resource. First reference found was resource [a-zA-Z]+/[0-9]+ in path [a-zA-Z]+.[a-zA-Z]+"));
|
||||
}
|
||||
|
||||
private static List<String> toStringList(List<UriType> theUriType) {
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
package ca.uhn.fhir.jpa.demo;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.to.FhirTesterMvcConfig;
|
||||
import ca.uhn.fhir.to.TesterConfig;
|
||||
|
||||
//@formatter:off
|
||||
/**
|
||||
* This spring config file configures the web testing module. It serves two
|
||||
* purposes:
|
||||
* 1. It imports FhirTesterMvcConfig, which is the spring config for the
|
||||
* tester itself
|
||||
* 2. It tells the tester which server(s) to talk to, via the testerConfig()
|
||||
* method below
|
||||
*/
|
||||
@Configuration
|
||||
@Import(FhirTesterMvcConfig.class)
|
||||
public class FhirTesterConfigDstu3 {
|
||||
|
||||
/**
|
||||
* This bean tells the testing webpage which servers it should configure itself
|
||||
* to communicate with. In this example we configure it to talk to the local
|
||||
* server, as well as one public server. If you are creating a project to
|
||||
* deploy somewhere else, you might choose to only put your own server's
|
||||
* address here.
|
||||
*
|
||||
* Note the use of the ${serverBase} variable below. This will be replaced with
|
||||
* the base URL as reported by the server itself. Often for a simple Tomcat
|
||||
* (or other container) installation, this will end up being something
|
||||
* like "http://localhost:8080/hapi-fhir-jpaserver-example". If you are
|
||||
* deploying your server to a place with a fully qualified domain name,
|
||||
* you might want to use that instead of using the variable.
|
||||
*/
|
||||
@Bean
|
||||
public TesterConfig testerConfig() {
|
||||
TesterConfig retVal = new TesterConfig();
|
||||
retVal
|
||||
.addServer()
|
||||
.withId("home")
|
||||
.withFhirVersion(FhirVersionEnum.DSTU3)
|
||||
.withBaseUrl("${serverBase}/baseDstu3")
|
||||
.withName("Local Tester")
|
||||
.addServer()
|
||||
.withId("hapi")
|
||||
.withFhirVersion(FhirVersionEnum.DSTU3)
|
||||
.withBaseUrl("http://fhirtest.uhn.ca/baseDstu3")
|
||||
.withName("Public HAPI Test Server");
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
//@formatter:on
|
|
@ -46,22 +46,20 @@ public class JpaServerDemo extends RestfulServer {
|
|||
protected void initialize() throws ServletException {
|
||||
super.initialize();
|
||||
|
||||
/*
|
||||
/*
|
||||
* We want to support FHIR DSTU2 format. This means that the server
|
||||
* will use the DSTU2 bundle format and other DSTU2 encoding changes.
|
||||
*
|
||||
* If you want to use DSTU1 instead, change the following line, and
|
||||
* change the 2 occurrences of dstu2 in web.xml to dstu1
|
||||
*/
|
||||
FhirVersionEnum fhirVersion = FhirVersionEnum.DSTU2;
|
||||
FhirContext context = new FhirContext(fhirVersion);
|
||||
|
||||
setFhirContext(context);
|
||||
FhirVersionEnum fhirVersion = FhirVersionEnum.DSTU3;
|
||||
setFhirContext(new FhirContext(fhirVersion));
|
||||
|
||||
// Get the spring context from the web container (it's declared in web.xml)
|
||||
myAppCtx = ContextLoaderListener.getCurrentWebApplicationContext();
|
||||
|
||||
/*
|
||||
/*
|
||||
* The BaseJavaConfigDstu2.java class is a spring configuration
|
||||
* file which is automatically generated as a part of hapi-fhir-jpaserver-base and
|
||||
* contains bean definitions for a resource provider for each resource type
|
||||
|
@ -78,8 +76,8 @@ public class JpaServerDemo extends RestfulServer {
|
|||
}
|
||||
List<IResourceProvider> beans = myAppCtx.getBean(resourceProviderBeanName, List.class);
|
||||
setResourceProviders(beans);
|
||||
|
||||
/*
|
||||
|
||||
/*
|
||||
* The system provider implements non-resource-type methods, such as
|
||||
* transaction, and global history.
|
||||
*/
|
||||
|
@ -174,15 +172,15 @@ public class JpaServerDemo extends RestfulServer {
|
|||
}
|
||||
|
||||
/*
|
||||
* If you are hosting this server at a specific DNS name, the server will try to
|
||||
* If you are hosting this server at a specific DNS name, the server will try to
|
||||
* figure out the FHIR base URL based on what the web container tells it, but
|
||||
* this doesn't always work. If you are setting links in your search bundles that
|
||||
* just refer to "localhost", you might want to use a server address strategy:
|
||||
*/
|
||||
//setServerAddressStrategy(new HardcodedServerAddressStrategy("http://mydomain.com/fhir/baseDstu2"));
|
||||
|
||||
|
||||
/*
|
||||
* If you are using DSTU3+, you may want to add a terminology uploader, which allows
|
||||
* If you are using DSTU3+, you may want to add a terminology uploader, which allows
|
||||
* uploading of external terminologies such as Snomed CT. Note that this uploader
|
||||
* does not have any security attached (any anonymous user may use it by default)
|
||||
* so it is a potential security vulnerability. Consider using an AuthorizationInterceptor
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<context-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>
|
||||
ca.uhn.fhir.jpa.demo.FhirServerConfig
|
||||
ca.uhn.fhir.jpa.demo.FhirServerConfigDstu3
|
||||
</param-value>
|
||||
</context-param>
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
|||
</init-param>
|
||||
<init-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>ca.uhn.fhir.jpa.demo.FhirTesterConfig</param-value>
|
||||
<param-value>ca.uhn.fhir.jpa.demo.FhirTesterConfigDstu3</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>2</load-on-startup>
|
||||
</servlet>
|
||||
|
@ -42,14 +42,14 @@
|
|||
</init-param>
|
||||
<init-param>
|
||||
<param-name>FhirVersion</param-name>
|
||||
<param-value>DSTU2</param-value>
|
||||
<param-value>DSTU3</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>fhirServlet</servlet-name>
|
||||
<url-pattern>/baseDstu2/*</url-pattern>
|
||||
<url-pattern>/baseDstu3/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
|
|
|
@ -7,13 +7,13 @@ import java.io.IOException;
|
|||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
import ca.uhn.fhir.rest.client.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
|
@ -21,7 +21,7 @@ import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
|||
public class ExampleServerIT {
|
||||
|
||||
private static IGenericClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forDstu2();
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerIT.class);
|
||||
|
||||
private static int ourPort;
|
||||
|
@ -34,11 +34,11 @@ public class ExampleServerIT {
|
|||
String methodName = "testCreateResourceConditional";
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.addName().addFamily(methodName);
|
||||
pt.addName().setFamily(methodName);
|
||||
IIdType id = ourClient.create().resource(pt).execute().getId();
|
||||
|
||||
Patient pt2 = ourClient.read().resource(Patient.class).withId(id).execute();
|
||||
assertEquals(methodName, pt2.getName().get(0).getFamily().get(0).getValue());
|
||||
assertEquals(methodName, pt2.getName().get(0).getFamily());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
|
@ -72,7 +72,7 @@ public class ExampleServerIT {
|
|||
|
||||
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
|
||||
ourServerBase = "http://localhost:" + ourPort + "/baseDstu2";
|
||||
ourServerBase = "http://localhost:" + ourPort + "/baseDstu3";
|
||||
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
|
||||
ourClient.registerInterceptor(new LoggingInterceptor(true));
|
||||
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
package ca.uhn.fhirtest.config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu2;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu2;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ResponseValidatingInterceptor;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import ca.uhn.fhirtest.interceptor.TdlSecurityInterceptor;
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.hibernate.dialect.DerbyTenSevenDialect;
|
||||
|
@ -13,18 +17,16 @@ import org.springframework.beans.factory.annotation.Autowire;
|
|||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu2;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu2;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhirtest.interceptor.TdlSecurityInterceptor;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Properties;
|
||||
|
||||
@Configuration
|
||||
@Import(CommonConfig.class)
|
||||
|
@ -113,6 +115,49 @@ public class TdlDstu2Config extends BaseJavaConfigDstu2 {
|
|||
return extraProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean which validates incoming requests
|
||||
*/
|
||||
@Bean
|
||||
@Lazy
|
||||
public RequestValidatingInterceptor requestValidatingInterceptor() {
|
||||
RequestValidatingInterceptor requestValidator = new RequestValidatingInterceptor();
|
||||
requestValidator.setFailOnSeverity(null);
|
||||
requestValidator.setAddResponseHeaderOnSeverity(null);
|
||||
requestValidator.setAddResponseOutcomeHeaderOnSeverity(ResultSeverityEnum.INFORMATION);
|
||||
requestValidator.addValidatorModule(instanceValidatorDstu2());
|
||||
requestValidator.setIgnoreValidatorExceptions(true);
|
||||
|
||||
return requestValidator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean which validates outgoing responses
|
||||
*/
|
||||
@Bean
|
||||
@Lazy
|
||||
public ResponseValidatingInterceptor responseValidatingInterceptor() {
|
||||
ResponseValidatingInterceptor responseValidator = new ResponseValidatingInterceptor();
|
||||
responseValidator.setResponseHeaderValueNoIssues("Validation did not detect any issues");
|
||||
responseValidator.setFailOnSeverity(null);
|
||||
responseValidator.setAddResponseHeaderOnSeverity(null);
|
||||
responseValidator.setAddResponseOutcomeHeaderOnSeverity(ResultSeverityEnum.INFORMATION);
|
||||
responseValidator.addExcludeOperationType(RestOperationTypeEnum.METADATA);
|
||||
responseValidator.addExcludeOperationType(RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE);
|
||||
responseValidator.addExcludeOperationType(RestOperationTypeEnum.EXTENDED_OPERATION_SERVER);
|
||||
responseValidator.addExcludeOperationType(RestOperationTypeEnum.EXTENDED_OPERATION_TYPE);
|
||||
responseValidator.addExcludeOperationType(RestOperationTypeEnum.GET_PAGE);
|
||||
responseValidator.addExcludeOperationType(RestOperationTypeEnum.HISTORY_INSTANCE);
|
||||
responseValidator.addExcludeOperationType(RestOperationTypeEnum.HISTORY_SYSTEM);
|
||||
responseValidator.addExcludeOperationType(RestOperationTypeEnum.HISTORY_TYPE);
|
||||
responseValidator.addExcludeOperationType(RestOperationTypeEnum.SEARCH_SYSTEM);
|
||||
responseValidator.addExcludeOperationType(RestOperationTypeEnum.SEARCH_TYPE);
|
||||
responseValidator.addValidatorModule(instanceValidatorDstu2());
|
||||
responseValidator.setIgnoreValidatorExceptions(true);
|
||||
|
||||
return responseValidator;
|
||||
}
|
||||
|
||||
@Bean(autowire=Autowire.BY_TYPE)
|
||||
public IServerInterceptor subscriptionSecurityInterceptor() {
|
||||
return new SubscriptionsRequireManualActivationInterceptorDstu2();
|
||||
|
|
|
@ -1,30 +1,28 @@
|
|||
package ca.uhn.fhirtest.config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu2;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import ca.uhn.fhirtest.interceptor.PublicSecurityInterceptor;
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.hibernate.dialect.PostgreSQL94Dialect;
|
||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowire;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu2;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu2;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhirtest.interceptor.PublicSecurityInterceptor;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Properties;
|
||||
|
||||
@Configuration
|
||||
@Import(CommonConfig.class)
|
||||
|
@ -114,6 +112,22 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
|
|||
return extraProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean which validates incoming requests
|
||||
*/
|
||||
@Bean
|
||||
@Lazy
|
||||
public RequestValidatingInterceptor requestValidatingInterceptor() {
|
||||
RequestValidatingInterceptor requestValidator = new RequestValidatingInterceptor();
|
||||
requestValidator.setFailOnSeverity(null);
|
||||
requestValidator.setAddResponseHeaderOnSeverity(null);
|
||||
requestValidator.setAddResponseOutcomeHeaderOnSeverity(ResultSeverityEnum.INFORMATION);
|
||||
requestValidator.addValidatorModule(instanceValidatorDstu2());
|
||||
requestValidator.setIgnoreValidatorExceptions(true);
|
||||
|
||||
return requestValidator;
|
||||
}
|
||||
|
||||
// @Bean(autowire = Autowire.BY_TYPE)
|
||||
// public IServerInterceptor subscriptionSecurityInterceptor() {
|
||||
// return new SubscriptionsRequireManualActivationInterceptorDstu2();
|
||||
|
|
|
@ -26,6 +26,27 @@
|
|||
Web testing UI displayed an error when a transaction was pasted into the UI
|
||||
for a DSTU2 server. Thanks to Suresh Kumar for reporting!
|
||||
</action>
|
||||
<action type="add">
|
||||
DaoConfig#setAllowInlineMatchUrlReferences() now defaults to
|
||||
<![CDATA[<code>true</code>]]> since inline conditional references
|
||||
are now a part of the FHIR specification. Thanks to Jan Dědek for
|
||||
pointing this out!
|
||||
</action>
|
||||
<action type="add" issue="609">
|
||||
hapi-fhir-jpaserver-base now exposes a
|
||||
<![CDATA[<code>FhirInstanceValidator</code> bean named <code>"myInstanceValidatorDstu2"</code>]]>
|
||||
for DSTU2. A similar bean for DSTU3 was previously implemented.
|
||||
</action>
|
||||
<action type="add" issue="453">
|
||||
hapi-fhir-jpaserver-example project now defaults to STU3 mode instead of
|
||||
the previous DSTU2. Thanks to Joel Schneider for the pull request!
|
||||
</action>
|
||||
<action type="add" issue="534">
|
||||
JPA server now has a setting on the DaoConfig to force it to treat
|
||||
certain reference URLs or reference URL patterns as logical URLs instead
|
||||
of literal ones, meaning that the server will not try to resolve these
|
||||
URLs. Thanks to Eeva Turkka for the suggestion!
|
||||
</action>
|
||||
</release>
|
||||
<release version="2.3" date="2017-03-18">
|
||||
<action type="add">
|
||||
|
|
|
@ -174,6 +174,38 @@ public DaoConfig daoConfig() {
|
|||
return retVal;
|
||||
}]]></source>
|
||||
</subsection>
|
||||
|
||||
<subsection name="Logical References">
|
||||
|
||||
<p>
|
||||
In some cases, you may have references which are <i>Logical References</i>,
|
||||
which means that they act as an identifier and not necessarily as a literal
|
||||
web address.
|
||||
</p>
|
||||
<p>
|
||||
A common use for logical references is in references to conformance
|
||||
resources, such as ValueSets, StructureDefinitions, etc. For example,
|
||||
you might refer to the ValueSet
|
||||
<code>http://hl7.org/fhir/ValueSet/quantity-comparator</code>
|
||||
from your own resources. In this case, you are not neccesarily telling
|
||||
the server that this is a real address that it should resolve, but
|
||||
rather that this is an identifier for a ValueSet where
|
||||
<code>ValueSet.url</code> has the given URI/URL.
|
||||
</p>
|
||||
<p>
|
||||
HAPI can be configured to treat certain URI/URL patterns as
|
||||
logical by using the DaoConfig#setTreatReferencesAsLogical property
|
||||
(see <a href="./apidocs-jpaserver/ca/uhn/fhir/jpa/dao/DaoConfig.html#setTreatReferencesAsLogical-java.util.Set-">JavaDoc</a>).
|
||||
For example:
|
||||
</p>
|
||||
<code>
|
||||
// Treat specific URL as logical
|
||||
myDaoConfig.getTreatReferencesAsLogical().add("http://mysystem.com/ValueSet/cats-and-dogs");
|
||||
|
||||
// Treat all references with given prefix as logical
|
||||
myDaoConfig.getTreatReferencesAsLogical().add("http://mysystem.com/mysystem-vs-*");
|
||||
</code>
|
||||
</subsection>
|
||||
|
||||
</section>
|
||||
|
||||
|
|
Loading…
Reference in New Issue