Add support for $validate-code in JPA server
This commit is contained in:
parent
257908cf0a
commit
ddc66d3ed0
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.model.primitive;
|
package ca.uhn.fhir.model.primitive;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Core Library
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2015 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 ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||||
import net.sourceforge.cobertura.CoverageIgnore;
|
import net.sourceforge.cobertura.CoverageIgnore;
|
||||||
|
|
||||||
|
|
|
@ -59,16 +59,16 @@ public @interface OperationParam {
|
||||||
Class<? extends IBase> type() default IBase.class;
|
Class<? extends IBase> type() default IBase.class;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The minimum number of repetitions allowed for this child
|
* The minimum number of repetitions allowed for this child (default is 0)
|
||||||
*/
|
*/
|
||||||
int min() default 0;
|
int min() default 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The maximum number of repetitions allowed for this child. Should be
|
* The maximum number of repetitions allowed for this child. Should be
|
||||||
* set to {@link #MAX_UNLIMITED} if there is no limit to the number of
|
* set to {@link #MAX_UNLIMITED} if there is no limit to the number of
|
||||||
* repetitions.
|
* repetitions (default is 1)
|
||||||
*/
|
*/
|
||||||
int max() default MAX_UNLIMITED;
|
int max() default 1;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.rest.client.interceptor;
|
package ca.uhn.fhir.rest.client.interceptor;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Core Library
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2015 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 org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.client.methods.HttpRequestBase;
|
import org.apache.http.client.methods.HttpRequestBase;
|
||||||
|
|
|
@ -174,6 +174,10 @@
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-context-support</artifactId>
|
<artifactId>spring-context-support</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-test</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Hibernate -->
|
<!-- Hibernate -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -19,8 +19,8 @@ package ca.uhn.fhir.jpa.dao;
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
import static org.apache.commons.lang3.StringUtils.*;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
@ -115,7 +115,7 @@ import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||||
import ca.uhn.fhir.util.FhirTerser;
|
import ca.uhn.fhir.util.FhirTerser;
|
||||||
|
|
||||||
public abstract class BaseHapiFhirDao implements IDao {
|
public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
|
|
||||||
public static final String NS_JPA_PROFILE = "https://github.com/jamesagnew/hapi-fhir/ns/jpa/profile";
|
public static final String NS_JPA_PROFILE = "https://github.com/jamesagnew/hapi-fhir/ns/jpa/profile";
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiFhirDao.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiFhirDao.class);
|
||||||
|
@ -344,7 +344,7 @@ public abstract class BaseHapiFhirDao implements IDao {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected <T extends IBaseResource> IFhirResourceDao<T> getDao(Class<T> theType) {
|
protected <R extends IBaseResource> IFhirResourceDao<R> getDao(Class<R> theType) {
|
||||||
if (myResourceTypeToDao == null) {
|
if (myResourceTypeToDao == null) {
|
||||||
myResourceTypeToDao = new HashMap<Class<? extends IBaseResource>, IFhirResourceDao<?>>();
|
myResourceTypeToDao = new HashMap<Class<? extends IBaseResource>, IFhirResourceDao<?>>();
|
||||||
for (IFhirResourceDao<?> next : myResourceDaos) {
|
for (IFhirResourceDao<?> next : myResourceDaos) {
|
||||||
|
@ -358,7 +358,7 @@ public abstract class BaseHapiFhirDao implements IDao {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (IFhirResourceDao<T>) myResourceTypeToDao.get(theType);
|
return (IFhirResourceDao<R>) myResourceTypeToDao.get(theType);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TagDefinition getTag(TagTypeEnum theTagType, String theScheme, String theTerm, String theLabel) {
|
protected TagDefinition getTag(TagTypeEnum theTagType, String theScheme, String theTerm, String theLabel) {
|
||||||
|
@ -644,12 +644,12 @@ public abstract class BaseHapiFhirDao implements IDao {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected <T extends IResource> Set<Long> processMatchUrl(String theMatchUrl, Class<T> theResourceType) {
|
protected <R extends IResource> Set<Long> processMatchUrl(String theMatchUrl, Class<R> theResourceType) {
|
||||||
RuntimeResourceDefinition resourceDef = getContext().getResourceDefinition(theResourceType);
|
RuntimeResourceDefinition resourceDef = getContext().getResourceDefinition(theResourceType);
|
||||||
|
|
||||||
SearchParameterMap paramMap = translateMatchUrl(theMatchUrl, resourceDef);
|
SearchParameterMap paramMap = translateMatchUrl(theMatchUrl, resourceDef);
|
||||||
|
|
||||||
IFhirResourceDao<T> dao = getDao(theResourceType);
|
IFhirResourceDao<R> dao = getDao(theResourceType);
|
||||||
Set<Long> ids = dao.searchForIdsWithAndOr(paramMap);
|
Set<Long> ids = dao.searchForIdsWithAndOr(paramMap);
|
||||||
|
|
||||||
return ids;
|
return ids;
|
||||||
|
@ -899,6 +899,7 @@ public abstract class BaseHapiFhirDao implements IDao {
|
||||||
case DSTU1:
|
case DSTU1:
|
||||||
mySearchParamExtractor = new SearchParamExtractorDstu1(theContext);
|
mySearchParamExtractor = new SearchParamExtractorDstu1(theContext);
|
||||||
break;
|
break;
|
||||||
|
case DSTU2_HL7ORG:
|
||||||
case DEV:
|
case DEV:
|
||||||
throw new IllegalStateException("Don't know how to handle version: " + myContext.getVersion().getVersion());
|
throw new IllegalStateException("Don't know how to handle version: " + myContext.getVersion().getVersion());
|
||||||
}
|
}
|
||||||
|
@ -917,7 +918,7 @@ public abstract class BaseHapiFhirDao implements IDao {
|
||||||
return toResource(type.getImplementingClass(), theEntity);
|
return toResource(type.getImplementingClass(), theEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected <T extends IBaseResource> T toResource(Class<T> theResourceType, BaseHasResource theEntity) {
|
protected <R extends IBaseResource> R toResource(Class<R> theResourceType, BaseHasResource theEntity) {
|
||||||
String resourceText = null;
|
String resourceText = null;
|
||||||
switch (theEntity.getEncoding()) {
|
switch (theEntity.getEncoding()) {
|
||||||
case JSON:
|
case JSON:
|
||||||
|
@ -933,7 +934,7 @@ public abstract class BaseHapiFhirDao implements IDao {
|
||||||
}
|
}
|
||||||
|
|
||||||
IParser parser = theEntity.getEncoding().newParser(getContext(theEntity.getFhirVersion()));
|
IParser parser = theEntity.getEncoding().newParser(getContext(theEntity.getFhirVersion()));
|
||||||
T retVal;
|
R retVal;
|
||||||
try {
|
try {
|
||||||
retVal = parser.parseResource(theResourceType, resourceText);
|
retVal = parser.parseResource(theResourceType, resourceText);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -955,9 +956,9 @@ public abstract class BaseHapiFhirDao implements IDao {
|
||||||
IResource res = (IResource) retVal;
|
IResource res = (IResource) retVal;
|
||||||
res.setId(theEntity.getIdDt());
|
res.setId(theEntity.getIdDt());
|
||||||
|
|
||||||
res.getResourceMetadata().put(ResourceMetadataKeyEnum.VERSION_ID, theEntity.getVersion());
|
ResourceMetadataKeyEnum.VERSION.put(res, Long.toString(theEntity.getVersion()));
|
||||||
res.getResourceMetadata().put(ResourceMetadataKeyEnum.PUBLISHED, theEntity.getPublished());
|
ResourceMetadataKeyEnum.PUBLISHED.put(res, theEntity.getPublished());
|
||||||
res.getResourceMetadata().put(ResourceMetadataKeyEnum.UPDATED, theEntity.getUpdated());
|
ResourceMetadataKeyEnum.UPDATED.put(res, theEntity.getUpdated());
|
||||||
|
|
||||||
if (theEntity.getTitle() != null) {
|
if (theEntity.getTitle() != null) {
|
||||||
ResourceMetadataKeyEnum.TITLE.put(res, theEntity.getTitle());
|
ResourceMetadataKeyEnum.TITLE.put(res, theEntity.getTitle());
|
||||||
|
@ -1038,9 +1039,10 @@ public abstract class BaseHapiFhirDao implements IDao {
|
||||||
return updateEntity(theResource, entity, theUpdateHistory, theDeletedTimestampOrNull, true, true);
|
return updateEntity(theResource, entity, theUpdateHistory, theDeletedTimestampOrNull, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
protected ResourceTable updateEntity(final IResource theResource, ResourceTable entity, boolean theUpdateHistory, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion) {
|
protected ResourceTable updateEntity(final IResource theResource, ResourceTable entity, boolean theUpdateHistory, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion) {
|
||||||
|
|
||||||
validateResourceForStorage(theResource);
|
validateResourceForStorage((T) theResource);
|
||||||
|
|
||||||
if (entity.getPublished() == null) {
|
if (entity.getPublished() == null) {
|
||||||
entity.setPublished(new Date());
|
entity.setPublished(new Date());
|
||||||
|
@ -1216,12 +1218,15 @@ public abstract class BaseHapiFhirDao implements IDao {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subclasses may override to provide specific behaviour
|
* This method is invoked immediately before storing a new resource, or an
|
||||||
|
* update to an existing resource to allow the DAO to ensure that it is valid
|
||||||
|
* for persistence. By default, no validation is performed, but subclasses
|
||||||
|
* may override to provide specific behaviour.
|
||||||
*
|
*
|
||||||
* @param theResource
|
* @param theResource
|
||||||
* The resource that is about to be persisted
|
* The resource that is about to be persisted
|
||||||
*/
|
*/
|
||||||
protected void validateResourceForStorage(IResource theResource) {
|
protected void validateResourceForStorage(T theResource) {
|
||||||
// nothing
|
// nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -131,7 +131,7 @@ import ca.uhn.fhir.util.FhirTerser;
|
||||||
import ca.uhn.fhir.util.ObjectUtil;
|
import ca.uhn.fhir.util.ObjectUtil;
|
||||||
|
|
||||||
@Transactional(propagation = Propagation.REQUIRED)
|
@Transactional(propagation = Propagation.REQUIRED)
|
||||||
public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseHapiFhirDao implements IFhirResourceDao<T> {
|
public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseHapiFhirDao<T> implements IFhirResourceDao<T> {
|
||||||
|
|
||||||
static final String OO_SEVERITY_WARN = "warning";
|
static final String OO_SEVERITY_WARN = "warning";
|
||||||
static final String OO_SEVERITY_INFO = "information";
|
static final String OO_SEVERITY_INFO = "information";
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.dao;
|
package ca.uhn.fhir.jpa.dao;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2015 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 javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||||
|
@ -7,7 +27,6 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.model.api.IResource;
|
|
||||||
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
|
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Questionnaire;
|
import ca.uhn.fhir.model.dstu2.resource.Questionnaire;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.QuestionnaireResponse;
|
import ca.uhn.fhir.model.dstu2.resource.QuestionnaireResponse;
|
||||||
|
@ -39,7 +58,7 @@ public class FhirResourceDaoQuestionnaireResponseDstu2 extends FhirResourceDaoDs
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void validateResourceForStorage(IResource theResource) {
|
protected void validateResourceForStorage(QuestionnaireResponse theResource) {
|
||||||
super.validateResourceForStorage(theResource);
|
super.validateResourceForStorage(theResource);
|
||||||
if (!myValidateResponses) {
|
if (!myValidateResponses) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -0,0 +1,187 @@
|
||||||
|
package ca.uhn.fhir.jpa.dao;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.binary.StringUtils;
|
||||||
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.entity.BaseHasResource;
|
||||||
|
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
|
||||||
|
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.ValueSet;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.ValueSet.CodeSystemConcept;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.ValueSet.ComposeInclude;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.ValueSet.ComposeIncludeConcept;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.ValueSet.ExpansionContains;
|
||||||
|
import ca.uhn.fhir.model.primitive.CodeDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.UriDt;
|
||||||
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
|
|
||||||
|
public class FhirResourceDaoValueSetDstu2 extends FhirResourceDaoDstu2<ValueSet>implements IFhirResourceDaoValueSet<ValueSet> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValueSet expand(IIdType theId, StringDt theFilter) {
|
||||||
|
ValueSet retVal = new ValueSet();
|
||||||
|
retVal.setDate(DateTimeDt.withCurrentTime());
|
||||||
|
|
||||||
|
BaseHasResource sourceEntity = readEntity(theId);
|
||||||
|
if (sourceEntity == null) {
|
||||||
|
throw new ResourceNotFoundException(theId);
|
||||||
|
}
|
||||||
|
ValueSet source = (ValueSet) toResource(sourceEntity);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add composed concepts
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (ComposeInclude nextInclude : source.getCompose().getInclude()) {
|
||||||
|
for (ComposeIncludeConcept next : nextInclude.getConcept()) {
|
||||||
|
if (theFilter == null || theFilter.isEmpty()) {
|
||||||
|
addCompose(retVal, nextInclude.getSystem(), next.getCode(), next.getDisplay());
|
||||||
|
} else {
|
||||||
|
String filter = theFilter.getValue().toLowerCase();
|
||||||
|
if (next.getDisplay().toLowerCase().contains(filter) || next.getCode().toLowerCase().contains(filter)) {
|
||||||
|
addCompose(retVal, nextInclude.getSystem(), next.getCode(), next.getDisplay());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add defined concepts
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (CodeSystemConcept next : source.getCodeSystem().getConcept()) {
|
||||||
|
addCompose(theFilter, retVal, source, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addCompose(StringDt theFilter, ValueSet theValueSetToPopulate, ValueSet theSourceValueSet, CodeSystemConcept theConcept) {
|
||||||
|
if (theFilter == null || theFilter.isEmpty()) {
|
||||||
|
addCompose(theValueSetToPopulate, theSourceValueSet.getCodeSystem().getSystem(), theConcept.getCode(), theConcept.getDisplay());
|
||||||
|
} else {
|
||||||
|
String filter = theFilter.getValue().toLowerCase();
|
||||||
|
if (theConcept.getDisplay().toLowerCase().contains(filter) || theConcept.getCode().toLowerCase().contains(filter)) {
|
||||||
|
addCompose(theValueSetToPopulate, theSourceValueSet.getCodeSystem().getSystem(), theConcept.getCode(), theConcept.getDisplay());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (CodeSystemConcept nextChild : theConcept.getConcept()) {
|
||||||
|
addCompose(theFilter, theValueSetToPopulate, theSourceValueSet, nextChild);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addCompose(ValueSet retVal, String theSystem, String theCode, String theDisplay) {
|
||||||
|
if (isBlank(theCode)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ExpansionContains contains = retVal.getExpansion().addContains();
|
||||||
|
contains.setSystem(theSystem);
|
||||||
|
contains.setCode(theCode);
|
||||||
|
contains.setDisplay(theDisplay);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult validateCode(UriDt theValueSetIdentifier, IIdType theId, CodeDt theCode, UriDt theSystem, StringDt theDisplay,
|
||||||
|
CodingDt theCoding, CodeableConceptDt theCodeableConcept) {
|
||||||
|
List<IIdType> valueSetIds;
|
||||||
|
|
||||||
|
boolean haveCodeableConcept = theCodeableConcept != null && theCodeableConcept.getCoding().size() > 0;
|
||||||
|
boolean haveCoding = theCoding != null && theCoding.isEmpty() == false;
|
||||||
|
boolean haveCode = theCode != null && theCode.isEmpty() == false;
|
||||||
|
|
||||||
|
if (!haveCodeableConcept && !haveCoding && !haveCode) {
|
||||||
|
throw new InvalidRequestException("No code, coding, or codeableConcept provided to validate");
|
||||||
|
}
|
||||||
|
if (!(haveCodeableConcept ^ haveCoding ^ haveCode)) {
|
||||||
|
throw new InvalidRequestException("$validate-code can only validate (system AND code) OR (coding) OR (codeableConcept)");
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean haveIdentifierParam = theValueSetIdentifier != null && theValueSetIdentifier.isEmpty() == false;
|
||||||
|
if (theId != null) {
|
||||||
|
valueSetIds = Collections.singletonList((IIdType) theId);
|
||||||
|
} else if (haveIdentifierParam) {
|
||||||
|
Set<Long> ids = searchForIds(ValueSet.SP_IDENTIFIER, new TokenParam(null, theValueSetIdentifier.getValue()));
|
||||||
|
valueSetIds = new ArrayList<IIdType>();
|
||||||
|
for (Long next : ids) {
|
||||||
|
valueSetIds.add(new IdDt("ValueSet", next));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (theCode == null || theCode.isEmpty()) {
|
||||||
|
throw new InvalidRequestException("Either ValueSet ID or ValueSet identifier or system and code must be provided. Unable to validate.");
|
||||||
|
}
|
||||||
|
Set<Long> ids = searchForIds(ValueSet.SP_CODE, new TokenParam(toStringOrNull(theSystem), theCode.getValue()));
|
||||||
|
valueSetIds = new ArrayList<IIdType>();
|
||||||
|
for (Long next : ids) {
|
||||||
|
valueSetIds.add(new IdDt("ValueSet", next));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (IIdType nextId : valueSetIds) {
|
||||||
|
ValueSet expansion = expand(nextId, null);
|
||||||
|
List<ExpansionContains> contains = expansion.getExpansion().getContains();
|
||||||
|
ValidateCodeResult result = validateCodeIsInContains(contains, toStringOrNull(theSystem), toStringOrNull(theCode), theCoding, theCodeableConcept);
|
||||||
|
if (result != null) {
|
||||||
|
if (theDisplay != null && isNotBlank(theDisplay.getValue()) && isNotBlank(result.getDisplay())) {
|
||||||
|
if (!theDisplay.getValue().equals(result.getDisplay())) {
|
||||||
|
return new ValidateCodeResult(false, "Display for code does not match", result.getDisplay());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ValidateCodeResult(false, "Code not found", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toStringOrNull(IPrimitiveType<String> thePrimitive) {
|
||||||
|
return thePrimitive != null ? thePrimitive.getValue() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult validateCodeIsInContains(List<ExpansionContains> contains, String theSystem, String theCode, CodingDt theCoding,
|
||||||
|
CodeableConceptDt theCodeableConcept) {
|
||||||
|
for (ExpansionContains nextCode : contains) {
|
||||||
|
ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult result = validateCodeIsInContains(nextCode.getContains(), theSystem, theCode, theCoding, theCodeableConcept);
|
||||||
|
if (result != null) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String system = nextCode.getSystem();
|
||||||
|
String code = nextCode.getCode();
|
||||||
|
|
||||||
|
if (isNotBlank(theCode)) {
|
||||||
|
if (theCode.equals(code) && (isBlank(theSystem) || theSystem.equals(system))) {
|
||||||
|
return new ValidateCodeResult(true, "Validation succeeded", nextCode.getDisplay());
|
||||||
|
}
|
||||||
|
} else if (theCoding != null) {
|
||||||
|
if (StringUtils.equals(system, theCoding.getSystem()) && StringUtils.equals(code, theCoding.getCode())) {
|
||||||
|
return new ValidateCodeResult(true, "Validation succeeded", nextCode.getDisplay());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (CodingDt next : theCodeableConcept.getCoding()) {
|
||||||
|
if (StringUtils.equals(system, next.getSystem()) && StringUtils.equals(code, next.getCode())) {
|
||||||
|
return new ValidateCodeResult(true, "Validation succeeded", nextCode.getDisplay());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package ca.uhn.fhir.jpa.dao;
|
||||||
|
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
|
||||||
|
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.ValueSet;
|
||||||
|
import ca.uhn.fhir.model.primitive.CodeDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.UriDt;
|
||||||
|
|
||||||
|
public interface IFhirResourceDaoValueSet<T extends IBaseResource> extends IFhirResourceDao<T> {
|
||||||
|
|
||||||
|
ValueSet expand(IIdType theId, StringDt theFilter);
|
||||||
|
|
||||||
|
ValidateCodeResult validateCode(UriDt theValueSetIdentifier, IIdType theId, CodeDt theCode, UriDt theSystem, StringDt theDisplay, CodingDt theCoding, CodeableConceptDt theCodeableConcept);
|
||||||
|
|
||||||
|
public class ValidateCodeResult {
|
||||||
|
private String myDisplay;
|
||||||
|
private String myMessage;
|
||||||
|
private boolean myResult;
|
||||||
|
|
||||||
|
public ValidateCodeResult(boolean theResult, String theMessage, String theDisplay) {
|
||||||
|
super();
|
||||||
|
myResult = theResult;
|
||||||
|
myMessage = theMessage;
|
||||||
|
myDisplay = theDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplay() {
|
||||||
|
return myDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return myMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isResult() {
|
||||||
|
return myResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -63,6 +63,7 @@ import ca.uhn.fhir.model.dstu2.resource.Conformance.RestSecurity;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Patient.Communication;
|
import ca.uhn.fhir.model.dstu2.resource.Patient.Communication;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Questionnaire;
|
import ca.uhn.fhir.model.dstu2.resource.Questionnaire;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.ValueSet;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.RestfulSecurityServiceEnum;
|
import ca.uhn.fhir.model.dstu2.valueset.RestfulSecurityServiceEnum;
|
||||||
import ca.uhn.fhir.model.primitive.BaseDateTimeDt;
|
import ca.uhn.fhir.model.primitive.BaseDateTimeDt;
|
||||||
import ca.uhn.fhir.model.primitive.IntegerDt;
|
import ca.uhn.fhir.model.primitive.IntegerDt;
|
||||||
|
@ -405,6 +406,12 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
||||||
public List<BaseResourceIndexedSearchParam> extractSearchParamTokens(ResourceTable theEntity, IResource theResource) {
|
public List<BaseResourceIndexedSearchParam> extractSearchParamTokens(ResourceTable theEntity, IResource theResource) {
|
||||||
ArrayList<BaseResourceIndexedSearchParam> retVal = new ArrayList<BaseResourceIndexedSearchParam>();
|
ArrayList<BaseResourceIndexedSearchParam> retVal = new ArrayList<BaseResourceIndexedSearchParam>();
|
||||||
|
|
||||||
|
String useSystem = null;
|
||||||
|
if (theResource instanceof ValueSet) {
|
||||||
|
ValueSet vs = (ValueSet) theResource;
|
||||||
|
useSystem = vs.getCodeSystem().getSystem();
|
||||||
|
}
|
||||||
|
|
||||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
|
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
|
||||||
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
|
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
|
||||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.TOKEN) {
|
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.TOKEN) {
|
||||||
|
@ -466,7 +473,11 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
||||||
if (nextValue.isEmpty()) {
|
if (nextValue.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
systems.add(null);
|
if ("ValueSet.codeSystem.concept.code".equals(nextPath)) {
|
||||||
|
systems.add(useSystem);
|
||||||
|
} else {
|
||||||
|
systems.add(null);
|
||||||
|
}
|
||||||
codes.add(nextValue.getValueAsString());
|
codes.add(nextValue.getValueAsString());
|
||||||
} else if (nextObject instanceof CodingDt) {
|
} else if (nextObject instanceof CodingDt) {
|
||||||
CodingDt nextValue = (CodingDt) nextObject;
|
CodingDt nextValue = (CodingDt) nextObject;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.provider;
|
package ca.uhn.fhir.jpa.provider;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2015 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 ca.uhn.fhir.model.dstu2.resource.QuestionnaireResponse;
|
import ca.uhn.fhir.model.dstu2.resource.QuestionnaireResponse;
|
||||||
|
|
||||||
public class BaseJpaResourceProviderQuestionnaireResponseDstu2 extends JpaResourceProviderDstu2<QuestionnaireResponse> {
|
public class BaseJpaResourceProviderQuestionnaireResponseDstu2 extends JpaResourceProviderDstu2<QuestionnaireResponse> {
|
||||||
|
|
|
@ -1,116 +1,76 @@
|
||||||
package ca.uhn.fhir.jpa.provider;
|
package ca.uhn.fhir.jpa.provider;
|
||||||
|
|
||||||
/*
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
* #%L
|
|
||||||
* HAPI FHIR JPA Server
|
|
||||||
* %%
|
|
||||||
* Copyright (C) 2014 - 2015 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.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet;
|
||||||
|
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult;
|
||||||
|
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
|
||||||
|
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Parameters;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.ValueSet;
|
import ca.uhn.fhir.model.dstu2.resource.ValueSet;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.ValueSet.CodeSystemConcept;
|
import ca.uhn.fhir.model.primitive.BooleanDt;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.ValueSet.ComposeInclude;
|
import ca.uhn.fhir.model.primitive.CodeDt;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.ValueSet.ComposeIncludeConcept;
|
|
||||||
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.StringDt;
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.UriDt;
|
||||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Operation;
|
import ca.uhn.fhir.rest.annotation.Operation;
|
||||||
import ca.uhn.fhir.rest.annotation.OperationParam;
|
import ca.uhn.fhir.rest.annotation.OperationParam;
|
||||||
|
|
||||||
public class BaseJpaResourceProviderValueSetDstu2 extends JpaResourceProviderDstu2<ValueSet> {
|
public class BaseJpaResourceProviderValueSetDstu2 extends JpaResourceProviderDstu2<ValueSet> {
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
@Operation(name = "$expand", idempotent = true)
|
@Operation(name = "$expand", idempotent = true)
|
||||||
public ValueSet everything(HttpServletRequest theServletRequest, @IdParam IdDt theId, @OperationParam(name = "filter") StringDt theFilter) {
|
public ValueSet everything(
|
||||||
|
HttpServletRequest theServletRequest,
|
||||||
|
@IdParam IdDt theId,
|
||||||
|
@OperationParam(name = "filter") StringDt theFilter) {
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
startRequest(theServletRequest);
|
startRequest(theServletRequest);
|
||||||
try {
|
try {
|
||||||
ValueSet retVal = new ValueSet();
|
IFhirResourceDaoValueSet<ValueSet> dao = (IFhirResourceDaoValueSet<ValueSet>) getDao();
|
||||||
retVal.setDate(DateTimeDt.withCurrentTime());
|
return dao.expand(theId, theFilter);
|
||||||
|
|
||||||
ValueSet source = read(theServletRequest, theId);
|
|
||||||
|
|
||||||
Map<String, ComposeInclude> systemToCompose = new HashMap<String, ComposeInclude>();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add composed concepts
|
|
||||||
*/
|
|
||||||
|
|
||||||
for (ComposeInclude nextInclude : source.getCompose().getInclude()) {
|
|
||||||
for (ComposeIncludeConcept next : nextInclude.getConcept()) {
|
|
||||||
ComposeInclude include = null;
|
|
||||||
if (theFilter == null || theFilter.isEmpty()) {
|
|
||||||
if (include == null) {
|
|
||||||
include = getOrAddComposeInclude(retVal, systemToCompose, nextInclude.getSystem());
|
|
||||||
}
|
|
||||||
include.addConcept(next);
|
|
||||||
} else {
|
|
||||||
String filter = theFilter.getValue().toLowerCase();
|
|
||||||
if (next.getDisplay().toLowerCase().contains(filter) || next.getCode().toLowerCase().contains(filter)) {
|
|
||||||
if (include == null) {
|
|
||||||
include = getOrAddComposeInclude(retVal, systemToCompose, nextInclude.getSystem());
|
|
||||||
}
|
|
||||||
include.addConcept(next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add defined concepts
|
|
||||||
*/
|
|
||||||
|
|
||||||
ComposeInclude include = null;
|
|
||||||
for (CodeSystemConcept next : source.getCodeSystem().getConcept()) {
|
|
||||||
if (theFilter == null || theFilter.isEmpty()) {
|
|
||||||
if (include == null) {
|
|
||||||
include = getOrAddComposeInclude(retVal, systemToCompose, source.getCodeSystem().getSystem());
|
|
||||||
}
|
|
||||||
include.addConcept(new ComposeIncludeConcept().setCode(next.getCode()).setDisplay(next.getDisplay()));
|
|
||||||
} else {
|
|
||||||
String filter = theFilter.getValue().toLowerCase();
|
|
||||||
if (next.getDisplay().toLowerCase().contains(filter) || next.getCode().toLowerCase().contains(filter)) {
|
|
||||||
if (include == null) {
|
|
||||||
include = getOrAddComposeInclude(retVal, systemToCompose, source.getCodeSystem().getSystem());
|
|
||||||
}
|
|
||||||
include.addConcept(new ComposeIncludeConcept().setCode(next.getCode()).setDisplay(next.getDisplay()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return retVal;
|
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
endRequest(theServletRequest);
|
endRequest(theServletRequest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ComposeInclude getOrAddComposeInclude(ValueSet retVal, Map<String, ComposeInclude> systemToCompose, String system) {
|
//@formatter:off
|
||||||
ComposeInclude include;
|
@Operation(name = "$validate-code", idempotent = true, returnParameters= {
|
||||||
include = systemToCompose.get(system);
|
@OperationParam(name="result", type=BooleanDt.class, min=1),
|
||||||
if (include == null) {
|
@OperationParam(name="message", type=StringDt.class),
|
||||||
include = retVal.getCompose().addInclude();
|
@OperationParam(name="display", type=StringDt.class)
|
||||||
include.setSystem(system);
|
})
|
||||||
systemToCompose.put(system, include);
|
public Parameters everything(
|
||||||
}
|
HttpServletRequest theServletRequest,
|
||||||
return include;
|
@IdParam IdDt theId,
|
||||||
}
|
@OperationParam(name="identifier") UriDt theValueSetIdentifier,
|
||||||
|
@OperationParam(name="code") CodeDt theCode,
|
||||||
|
@OperationParam(name="system") UriDt theSystem,
|
||||||
|
@OperationParam(name="display") StringDt theDisplay,
|
||||||
|
@OperationParam(name="coding") CodingDt theCoding,
|
||||||
|
@OperationParam(name="codeableConcept") CodeableConceptDt theCodeableConcept
|
||||||
|
) {
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
startRequest(theServletRequest);
|
||||||
|
try {
|
||||||
|
IFhirResourceDaoValueSet<ValueSet> dao = (IFhirResourceDaoValueSet<ValueSet>) getDao();
|
||||||
|
ValidateCodeResult result = dao.validateCode(theValueSetIdentifier, theId, theCode, theSystem, theDisplay, theCoding, theCodeableConcept);
|
||||||
|
Parameters retVal = new Parameters();
|
||||||
|
retVal.addParameter().setName("result").setValue(new BooleanDt(result.isResult()));
|
||||||
|
if (isNotBlank(result.getMessage())) {
|
||||||
|
retVal.addParameter().setName("message").setValue(new StringDt(result.getMessage()));
|
||||||
|
}
|
||||||
|
if (isNotBlank(result.getDisplay())) {
|
||||||
|
retVal.addParameter().setName("display").setValue(new StringDt(result.getDisplay()));
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
} finally {
|
||||||
|
endRequest(theServletRequest);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,217 @@
|
||||||
|
package ca.uhn.fhir.jpa.dao;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult;
|
||||||
|
import ca.uhn.fhir.jpa.provider.ResourceProviderDstu2Test;
|
||||||
|
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
|
||||||
|
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.ValueSet;
|
||||||
|
import ca.uhn.fhir.model.primitive.CodeDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.UriDt;
|
||||||
|
|
||||||
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
|
@ContextConfiguration({ "/hapi-fhir-server-resourceproviders-dstu2.xml", "/fhir-jpabase-spring-test-config.xml" })
|
||||||
|
public class FhirResourceDaoValueSetDstu2Test {
|
||||||
|
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoValueSetDstu2Test.class);
|
||||||
|
|
||||||
|
private static IIdType vsid;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private FhirContext myCtx;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("mySystemDaoDstu2")
|
||||||
|
private IFhirSystemDao<Bundle> mySystemDao;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("myValueSetDaoDstu2")
|
||||||
|
private IFhirResourceDaoValueSet<ValueSet> myValueSetDao;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
@Transactional
|
||||||
|
public void before01() {
|
||||||
|
if (vsid == null) {
|
||||||
|
FhirSystemDaoDstu2Test.doDeleteEverything(mySystemDao);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
@Transactional
|
||||||
|
public void before02() {
|
||||||
|
if (vsid == null) {
|
||||||
|
ValueSet upload = myCtx.newXmlParser().parseResource(ValueSet.class, new InputStreamReader(ResourceProviderDstu2Test.class.getResourceAsStream("/extensional-case-2.xml")));
|
||||||
|
upload.setId("");
|
||||||
|
vsid = myValueSetDao.create(upload).getId().toUnqualifiedVersionless();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateCodeOperationByCodeAndSystemBad() {
|
||||||
|
UriDt valueSetIdentifier = null;
|
||||||
|
IdDt id = null;
|
||||||
|
CodeDt code = new CodeDt("8450-9-XXX");
|
||||||
|
UriDt system = new UriDt("http://loinc.org");
|
||||||
|
StringDt display = null;
|
||||||
|
CodingDt coding = null;
|
||||||
|
CodeableConceptDt codeableConcept = null;
|
||||||
|
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
|
||||||
|
assertFalse(result.isResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateCodeOperationByCodeAndSystemGood() {
|
||||||
|
UriDt valueSetIdentifier = null;
|
||||||
|
IdDt id = null;
|
||||||
|
CodeDt code = new CodeDt("8450-9");
|
||||||
|
UriDt system = new UriDt("http://loinc.org");
|
||||||
|
StringDt display = null;
|
||||||
|
CodingDt coding = null;
|
||||||
|
CodeableConceptDt codeableConcept = null;
|
||||||
|
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
|
||||||
|
assertTrue(result.isResult());
|
||||||
|
assertEquals("Systolic blood pressure--expiration", result.getDisplay());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateCodeOperationByIdentifierAndCodeAndSystem() {
|
||||||
|
UriDt valueSetIdentifier = new UriDt("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2");
|
||||||
|
IdDt id = null;
|
||||||
|
CodeDt code = new CodeDt("11378-7");
|
||||||
|
UriDt system = new UriDt("http://loinc.org");
|
||||||
|
StringDt display = null;
|
||||||
|
CodingDt coding = null;
|
||||||
|
CodeableConceptDt codeableConcept = null;
|
||||||
|
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
|
||||||
|
assertTrue(result.isResult());
|
||||||
|
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateCodeOperationByIdentifierAndCodeAndSystemAndBadDisplay() {
|
||||||
|
UriDt valueSetIdentifier = new UriDt("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2");
|
||||||
|
IdDt id = null;
|
||||||
|
CodeDt code = new CodeDt("11378-7");
|
||||||
|
UriDt system = new UriDt("http://loinc.org");
|
||||||
|
StringDt display = new StringDt("Systolic blood pressure at First encounterXXXX");
|
||||||
|
CodingDt coding = null;
|
||||||
|
CodeableConceptDt codeableConcept = null;
|
||||||
|
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
|
||||||
|
assertFalse(result.isResult());
|
||||||
|
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateCodeOperationByIdentifierAndCodeAndSystemAndGoodDisplay() {
|
||||||
|
UriDt valueSetIdentifier = new UriDt("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2");
|
||||||
|
IdDt id = null;
|
||||||
|
CodeDt code = new CodeDt("11378-7");
|
||||||
|
UriDt system = new UriDt("http://loinc.org");
|
||||||
|
StringDt display = new StringDt("Systolic blood pressure at First encounter");
|
||||||
|
CodingDt coding = null;
|
||||||
|
CodeableConceptDt codeableConcept = null;
|
||||||
|
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
|
||||||
|
assertTrue(result.isResult());
|
||||||
|
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateCodeOperationByResourceIdAndCodeableConcept() {
|
||||||
|
UriDt valueSetIdentifier = null;
|
||||||
|
IIdType id = vsid;
|
||||||
|
CodeDt code = null;
|
||||||
|
UriDt system = null;
|
||||||
|
StringDt display = null;
|
||||||
|
CodingDt coding = null;
|
||||||
|
CodeableConceptDt codeableConcept = new CodeableConceptDt("http://loinc.org", "11378-7");
|
||||||
|
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
|
||||||
|
assertTrue(result.isResult());
|
||||||
|
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateCodeOperationByResourceIdAndCodeAndSystem() {
|
||||||
|
UriDt valueSetIdentifier = null;
|
||||||
|
IIdType id = vsid;
|
||||||
|
CodeDt code = new CodeDt("11378-7");
|
||||||
|
UriDt system = new UriDt("http://loinc.org");
|
||||||
|
StringDt display = null;
|
||||||
|
CodingDt coding = null;
|
||||||
|
CodeableConceptDt codeableConcept = null;
|
||||||
|
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
|
||||||
|
assertTrue(result.isResult());
|
||||||
|
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValueSetExpandOperation() throws IOException {
|
||||||
|
String resp;
|
||||||
|
|
||||||
|
ValueSet expanded = myValueSetDao.expand(vsid, null);
|
||||||
|
resp = myCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
|
ourLog.info(resp);
|
||||||
|
// @formatter:off
|
||||||
|
assertThat(resp,
|
||||||
|
stringContainsInOrder("<ValueSet xmlns=\"http://hl7.org/fhir\">",
|
||||||
|
"<expansion>",
|
||||||
|
"<contains>",
|
||||||
|
"<system value=\"http://loinc.org\"/>",
|
||||||
|
"<code value=\"11378-7\"/>",
|
||||||
|
"<display value=\"Systolic blood pressure at First encounter\"/>",
|
||||||
|
"</contains>",
|
||||||
|
"<contains>",
|
||||||
|
"<system value=\"http://loinc.org\"/>",
|
||||||
|
"<code value=\"8450-9\"/>",
|
||||||
|
"<display value=\"Systolic blood pressure--expiration\"/>",
|
||||||
|
"</contains>",
|
||||||
|
"</expansion>"
|
||||||
|
));
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Filter with display name
|
||||||
|
*/
|
||||||
|
|
||||||
|
expanded = myValueSetDao.expand(vsid, new StringDt("systolic"));
|
||||||
|
resp = myCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
|
ourLog.info(resp);
|
||||||
|
//@formatter:off
|
||||||
|
assertThat(resp, stringContainsInOrder(
|
||||||
|
"<code value=\"11378-7\"/>",
|
||||||
|
"<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Filter with code
|
||||||
|
*/
|
||||||
|
|
||||||
|
expanded = myValueSetDao.expand(vsid, new StringDt("11378"));
|
||||||
|
resp = myCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
|
ourLog.info(resp);
|
||||||
|
//@formatter:off
|
||||||
|
assertThat(resp, stringContainsInOrder(
|
||||||
|
"<code value=\"11378-7\"/>",
|
||||||
|
"<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||||
|
//@formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -428,8 +428,6 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateQuestionnaireResponseWithValidation() throws IOException {
|
public void testCreateQuestionnaireResponseWithValidation() throws IOException {
|
||||||
String methodName = "testCreateQuestionnaireResponseWithValidation";
|
|
||||||
|
|
||||||
ValueSet options = new ValueSet();
|
ValueSet options = new ValueSet();
|
||||||
options.getCodeSystem().setSystem("urn:system").addConcept().setCode("code0");
|
options.getCodeSystem().setSystem("urn:system").addConcept().setCode("code0");
|
||||||
IIdType optId = ourClient.create().resource(options).execute().getId();
|
IIdType optId = ourClient.create().resource(options).execute().getId();
|
||||||
|
@ -1508,21 +1506,21 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
assertThat(
|
assertThat(resp,
|
||||||
resp,
|
stringContainsInOrder("<ValueSet xmlns=\"http://hl7.org/fhir\">",
|
||||||
stringContainsInOrder("<ValueSet xmlns=\"http://hl7.org/fhir\">",
|
"<expansion>",
|
||||||
"<compose>",
|
"<contains>",
|
||||||
"<include>",
|
|
||||||
"<system value=\"http://loinc.org\"/>",
|
"<system value=\"http://loinc.org\"/>",
|
||||||
"<concept>",
|
|
||||||
"<code value=\"11378-7\"/>",
|
"<code value=\"11378-7\"/>",
|
||||||
"<display value=\"Systolic blood pressure at First encounter\"/>",
|
"<display value=\"Systolic blood pressure at First encounter\"/>",
|
||||||
"</concept>",
|
"</contains>",
|
||||||
"<concept>",
|
"<contains>",
|
||||||
|
"<system value=\"http://loinc.org\"/>",
|
||||||
"<code value=\"8450-9\"/>",
|
"<code value=\"8450-9\"/>",
|
||||||
"<display value=\"Systolic blood pressure--expiration\"/>",
|
"<display value=\"Systolic blood pressure--expiration\"/>",
|
||||||
"</concept>"
|
"</contains>",
|
||||||
));
|
"</expansion>"
|
||||||
|
));
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
} finally {
|
} finally {
|
||||||
IOUtils.closeQuietly(response.getEntity().getContent());
|
IOUtils.closeQuietly(response.getEntity().getContent());
|
||||||
|
|
|
@ -28,7 +28,8 @@
|
||||||
|
|
||||||
#foreach ( $res in $resources )
|
#foreach ( $res in $resources )
|
||||||
<bean id="my${res.name}Dao${versionCapitalized}"
|
<bean id="my${res.name}Dao${versionCapitalized}"
|
||||||
#if ( ${versionCapitalized} == 'Dstu2' && ( ${res.name} == 'Bundle' || ${res.name} == 'QuestionnaireResponse' ))
|
## Some resource types have customized DAOs for resource specific functionality
|
||||||
|
#if ( ${versionCapitalized} == 'Dstu2' && ( ${res.name} == 'Bundle' || ${res.name} == 'QuestionnaireResponse' || ${res.name} == 'ValueSet'))
|
||||||
class="ca.uhn.fhir.jpa.dao.FhirResourceDao${res.name}${versionCapitalized}">
|
class="ca.uhn.fhir.jpa.dao.FhirResourceDao${res.name}${versionCapitalized}">
|
||||||
#else
|
#else
|
||||||
class="ca.uhn.fhir.jpa.dao.FhirResourceDao${versionCapitalized}">
|
class="ca.uhn.fhir.jpa.dao.FhirResourceDao${versionCapitalized}">
|
||||||
|
|
5
pom.xml
5
pom.xml
|
@ -336,6 +336,11 @@
|
||||||
<artifactId>spring-orm</artifactId>
|
<artifactId>spring-orm</artifactId>
|
||||||
<version>${spring_version}</version>
|
<version>${spring_version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-test</artifactId>
|
||||||
|
<version>${spring_version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-tx</artifactId>
|
<artifactId>spring-tx</artifactId>
|
||||||
|
|
|
@ -93,6 +93,9 @@
|
||||||
a resourceType element) fail to parse with a confusing NullPointerException.
|
a resourceType element) fail to parse with a confusing NullPointerException.
|
||||||
Thanks to GitHub user @hugosoares for reporting!
|
Thanks to GitHub user @hugosoares for reporting!
|
||||||
</action>
|
</action>
|
||||||
|
<action type="add">
|
||||||
|
JPA server now implements the $validate-code operation
|
||||||
|
</action>
|
||||||
</release>
|
</release>
|
||||||
<release version="1.1" date="2015-07-13">
|
<release version="1.1" date="2015-07-13">
|
||||||
<action type="add">
|
<action type="add">
|
||||||
|
|
Loading…
Reference in New Issue