709 the conceptmap operation called translate needs to be implemented (#923)

The ConceptMap operation $translate has been implemented.
This commit is contained in:
Diederik Muylwyk 2018-05-10 10:52:56 -04:00 committed by GitHub
parent a0c40cf98a
commit d97fb8f5cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 6804 additions and 74 deletions

View File

@ -30,7 +30,6 @@ import org.slf4j.LoggerFactory;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;

View File

@ -91,7 +91,11 @@ ca.uhn.fhir.jpa.dao.SearchBuilder.invalidNumberPrefix=Unable to handle number pr
ca.uhn.fhir.jpa.provider.BaseJpaProvider.cantCombintAtAndSince=Unable to combine _at and _since parameters for history operation ca.uhn.fhir.jpa.provider.BaseJpaProvider.cantCombintAtAndSince=Unable to combine _at and _since parameters for history operation
ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.cannotCreateDuplicateConceptMapUrl=Can not create multiple ConceptMap resources with ConceptMap.url "{0}", already have one with resource ID: {1}
ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.cannotCreateDuplicateCodeSystemUri=Can not create multiple code systems with URI "{0}", already have one with resource ID: {1} ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.cannotCreateDuplicateCodeSystemUri=Can not create multiple code systems with URI "{0}", already have one with resource ID: {1}
ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.expansionTooLarge=Expansion of ValueSet produced too many codes (maximum {0}) - Operation aborted! ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.expansionTooLarge=Expansion of ValueSet produced too many codes (maximum {0}) - Operation aborted!
ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.expansionTooLarge=Expansion of ValueSet produced too many codes (maximum {0}) - Operation aborted!
ca.uhn.fhir.jpa.dao.dstu3.FhirResourceDaoConceptMapDstu3.matchesFound=Matches found!
ca.uhn.fhir.jpa.dao.dstu3.FhirResourceDaoConceptMapDstu3.noMatchesFound=No matches found!
ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoConceptMapR4.matchesFound=Matches found!
ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoConceptMapR4.noMatchesFound=No matches found!

View File

@ -469,6 +469,16 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava-testlib</artifactId>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>

View File

@ -79,13 +79,8 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice; import org.springframework.data.domain.Slice;
import org.springframework.data.domain.SliceImpl; import org.springframework.data.domain.SliceImpl;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.support.TransactionTemplate;
import javax.annotation.Nullable;
import javax.persistence.*; import javax.persistence.*;
import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.CriteriaQuery;
@ -335,6 +330,13 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
doExpungeEverythingQuery("DELETE from " + TermConceptParentChildLink.class.getSimpleName() + " d"); doExpungeEverythingQuery("DELETE from " + TermConceptParentChildLink.class.getSimpleName() + " d");
return null; return null;
}); });
txTemplate.execute(t -> {
doExpungeEverythingQuery("DELETE from " + TermConceptMapGroupElementTarget.class.getSimpleName() + " d");
doExpungeEverythingQuery("DELETE from " + TermConceptMapGroupElement.class.getSimpleName() + " d");
doExpungeEverythingQuery("DELETE from " + TermConceptMapGroup.class.getSimpleName() + " d");
doExpungeEverythingQuery("DELETE from " + TermConceptMap.class.getSimpleName() + " d");
return null;
});
txTemplate.execute(t -> { txTemplate.execute(t -> {
doExpungeEverythingQuery("DELETE from " + TermConceptProperty.class.getSimpleName() + " d"); doExpungeEverythingQuery("DELETE from " + TermConceptProperty.class.getSimpleName() + " d");
doExpungeEverythingQuery("DELETE from " + TermConceptDesignation.class.getSimpleName() + " d"); doExpungeEverythingQuery("DELETE from " + TermConceptDesignation.class.getSimpleName() + " d");

View File

@ -57,6 +57,16 @@ public class DaoConfig {
*/ */
private static final Integer DEFAULT_MAXIMUM_SEARCH_RESULT_COUNT_IN_TRANSACTION = null; private static final Integer DEFAULT_MAXIMUM_SEARCH_RESULT_COUNT_IN_TRANSACTION = null;
private IndexEnabledEnum myIndexMissingFieldsEnabled = IndexEnabledEnum.DISABLED; private IndexEnabledEnum myIndexMissingFieldsEnabled = IndexEnabledEnum.DISABLED;
/**
* Default value for {@link #setTranslationCachesExpireAfterWriteInMinutes(Long)}: 60 minutes
*
* @see #setTranslationCachesExpireAfterWriteInMinutes(Long)
*/
public static final Long DEFAULT_TRANSLATION_CACHES_EXPIRE_AFTER_WRITE_IN_MINUTES = 60L;
/**
* update setter javadoc if default changes
*/
private Long myTranslationCachesExpireAfterWriteInMinutes = DEFAULT_TRANSLATION_CACHES_EXPIRE_AFTER_WRITE_IN_MINUTES;
/** /**
* update setter javadoc if default changes * update setter javadoc if default changes
*/ */
@ -557,6 +567,22 @@ public class DaoConfig {
myReuseCachedSearchResultsForMillis = theReuseCachedSearchResultsForMillis; myReuseCachedSearchResultsForMillis = theReuseCachedSearchResultsForMillis;
} }
/**
* Specifies the duration in minutes for which values will be retained after being
* written to the terminology translation cache. Defaults to 60.
*/
public Long getTranslationCachesExpireAfterWriteInMinutes() {
return myTranslationCachesExpireAfterWriteInMinutes;
}
/**
* Specifies the duration in minutes for which values will be retained after being
* written to the terminology translation cache. Defaults to 60.
*/
public void setTranslationCachesExpireAfterWriteInMinutes(Long translationCachesExpireAfterWriteInMinutes) {
myTranslationCachesExpireAfterWriteInMinutes = translationCachesExpireAfterWriteInMinutes;
}
/** /**
* This setting may be used to advise the server that any references found in * This setting may be used to advise the server that any references found in
* resources that have any of the base URLs given here will be replaced with * resources that have any of the base URLs given here will be replaced with

View File

@ -0,0 +1,30 @@
package ca.uhn.fhir.jpa.dao;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2018 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.jpa.term.TranslationRequest;
import ca.uhn.fhir.jpa.term.TranslationResult;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.hl7.fhir.instance.model.api.IBaseResource;
public interface IFhirResourceDaoConceptMap<T extends IBaseResource> extends IFhirResourceDao<T> {
TranslationResult translate(TranslationRequest theTranslationRequest, RequestDetails theRequestDetails);
}

View File

@ -28,6 +28,7 @@ import ca.uhn.fhir.jpa.search.JpaRuntimeSearchParam;
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc; import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
import ca.uhn.fhir.jpa.term.VersionIndependentConcept; import ca.uhn.fhir.jpa.term.VersionIndependentConcept;
import ca.uhn.fhir.jpa.util.BaseIterator; import ca.uhn.fhir.jpa.util.BaseIterator;
import ca.uhn.fhir.jpa.util.ScrollableResultsIterator;
import ca.uhn.fhir.model.api.*; import ca.uhn.fhir.model.api.*;
import ca.uhn.fhir.model.base.composite.BaseCodingDt; import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.base.composite.BaseIdentifierDt; import ca.uhn.fhir.model.base.composite.BaseIdentifierDt;
@ -59,9 +60,6 @@ import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import org.hibernate.ScrollMode; import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults; import org.hibernate.ScrollableResults;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.internal.SessionImpl;
import org.hibernate.query.Query; import org.hibernate.query.Query;
import org.hl7.fhir.dstu3.model.BaseResource; import org.hl7.fhir.dstu3.model.BaseResource;
import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IAnyResource;
@ -2193,7 +2191,7 @@ public class SearchBuilder implements ISearchBuilder {
Query<Long> hibernateQuery = (Query<Long>) query; Query<Long> hibernateQuery = (Query<Long>) query;
hibernateQuery.setFetchSize(myFetchSize); hibernateQuery.setFetchSize(myFetchSize);
ScrollableResults scroll = hibernateQuery.scroll(ScrollMode.FORWARD_ONLY); ScrollableResults scroll = hibernateQuery.scroll(ScrollMode.FORWARD_ONLY);
myResultsIterator = new ScrollableResultsIterator(scroll); myResultsIterator = new ScrollableResultsIterator<>(scroll);
// If the query resulted in extra results being requested // If the query resulted in extra results being requested
if (myAlsoIncludePids != null) { if (myAlsoIncludePids != null) {
@ -2275,42 +2273,6 @@ public class SearchBuilder implements ISearchBuilder {
} }
} }
public class ScrollableResultsIterator extends BaseIterator<Long> implements Iterator<Long> {
private Long myNext;
private ScrollableResults myScroll;
public ScrollableResultsIterator(ScrollableResults theScroll) {
myScroll = theScroll;
}
private void ensureHaveNext() {
if (myNext == null) {
if (myScroll.next()) {
myNext = (Long) myScroll.get(0);
} else {
myNext = NO_MORE;
}
}
}
@Override
public boolean hasNext() {
ensureHaveNext();
return myNext != NO_MORE;
}
@Override
public Long next() {
ensureHaveNext();
Validate.isTrue(myNext != NO_MORE);
Long next = myNext;
myNext = null;
return next;
}
}
private class UniqueIndexIterator implements Iterator<Long> { private class UniqueIndexIterator implements Iterator<Long> {
private final Set<String> myUniqueQueryStrings; private final Set<String> myUniqueQueryStrings;
private Iterator<Long> myWrap = null; private Iterator<Long> myWrap = null;

View File

@ -0,0 +1,41 @@
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.entity.TermConceptMap;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.Optional;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2018 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 interface ITermConceptMapDao extends JpaRepository<TermConceptMap, Long> {
@Query("DELETE FROM TermConceptMap cm WHERE cm.myId = :pid")
@Modifying
void deleteTermConceptMapById(@Param("pid") Long theId);
@Query("SELECT cm FROM TermConceptMap cm WHERE cm.myResourcePid = :resource_pid")
Optional<TermConceptMap> findTermConceptMapByResourcePid(@Param("resource_pid") Long theResourcePid);
@Query("SELECT cm FROM TermConceptMap cm WHERE cm.myUrl = :url")
Optional<TermConceptMap> findTermConceptMapByUrl(@Param("url") String theUrl);
}

View File

@ -0,0 +1,33 @@
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.entity.TermConceptMapGroup;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2018 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 interface ITermConceptMapGroupDao extends JpaRepository<TermConceptMapGroup, Long> {
@Query("DELETE FROM TermConceptMapGroup g WHERE g.myConceptMap.myId = :pid")
@Modifying
void deleteTermConceptMapGroupById(@Param("pid") Long theId);
}

View File

@ -0,0 +1,33 @@
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElement;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2018 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 interface ITermConceptMapGroupElementDao extends JpaRepository<TermConceptMapGroupElement, Long> {
@Query("DELETE FROM TermConceptMapGroupElement e WHERE e.myConceptMapGroup.myConceptMap.myId = :pid")
@Modifying
void deleteTermConceptMapGroupElementById(@Param("pid") Long theId);
}

View File

@ -0,0 +1,33 @@
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElementTarget;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2018 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 interface ITermConceptMapGroupElementTargetDao extends JpaRepository<TermConceptMapGroupElementTarget, Long> {
@Query("DELETE FROM TermConceptMapGroupElementTarget t WHERE t.myConceptMapGroupElement.myConceptMapGroup.myConceptMap.myId = :pid")
@Modifying
void deleteTermConceptMapGroupElementTargetById(@Param("pid") Long theId);
}

View File

@ -0,0 +1,176 @@
package ca.uhn.fhir.jpa.dao.dstu3;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2018 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.jpa.dao.IFhirResourceDaoConceptMap;
import ca.uhn.fhir.jpa.term.TranslationMatch;
import ca.uhn.fhir.jpa.term.TranslationRequest;
import ca.uhn.fhir.jpa.term.TranslationResult;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElement;
import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElementTarget;
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.hl7.fhir.convertors.VersionConvertor_30_40;
import org.hl7.fhir.dstu3.model.ConceptMap;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.*;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class FhirResourceDaoConceptMapDstu3 extends FhirResourceDaoDstu3<ConceptMap> implements IFhirResourceDaoConceptMap<ConceptMap> {
@Autowired
private IHapiTerminologySvc myHapiTerminologySvc;
@Override
public TranslationResult translate(TranslationRequest theTranslationRequest, RequestDetails theRequestDetails) {
if (theTranslationRequest.hasReverse() && theTranslationRequest.getReverseAsBoolean()) {
return buildReverseTranslationResult(myHapiTerminologySvc.translateWithReverse(theTranslationRequest));
}
return buildTranslationResult(myHapiTerminologySvc.translate(theTranslationRequest));
}
private TranslationResult buildTranslationResult(List<TermConceptMapGroupElementTarget> theTargets) {
TranslationResult retVal = new TranslationResult();
String msg;
if (theTargets.isEmpty()) {
retVal.setResult(new BooleanType(false));
msg = getContext().getLocalizer().getMessage(
FhirResourceDaoConceptMapDstu3.class,
"noMatchesFound");
retVal.setMessage(new StringType(msg));
} else {
retVal.setResult(new BooleanType(true));
msg = getContext().getLocalizer().getMessage(
FhirResourceDaoConceptMapDstu3.class,
"matchesFound");
retVal.setMessage(new StringType(msg));
TranslationMatch translationMatch;
Set<TermConceptMapGroupElementTarget> targetsToReturn = new HashSet<>();
for (TermConceptMapGroupElementTarget target : theTargets) {
if (targetsToReturn.add(target)) {
translationMatch = new TranslationMatch();
translationMatch.setEquivalence(new CodeType(target.getEquivalence().toCode()));
translationMatch.setConcept(
new Coding()
.setCode(target.getCode())
.setSystem(target.getSystem())
.setVersion(target.getSystemVersion())
.setDisplay(target.getDisplay())
);
translationMatch.setSource(new UriType(target.getConceptMapUrl()));
retVal.addMatch(translationMatch);
}
}
}
return retVal;
}
private TranslationResult buildReverseTranslationResult(List<TermConceptMapGroupElement> theElements) {
TranslationResult retVal = new TranslationResult();
String msg;
if (theElements.isEmpty()) {
retVal.setResult(new BooleanType(false));
msg = getContext().getLocalizer().getMessage(
FhirResourceDaoConceptMapDstu3.class,
"noMatchesFound");
retVal.setMessage(new StringType(msg));
} else {
retVal.setResult(new BooleanType(true));
msg = getContext().getLocalizer().getMessage(
FhirResourceDaoConceptMapDstu3.class,
"matchesFound");
retVal.setMessage(new StringType(msg));
TranslationMatch translationMatch;
Set<TermConceptMapGroupElement> elementsToReturn = new HashSet<>();
for (TermConceptMapGroupElement element : theElements) {
if (elementsToReturn.add(element)) {
translationMatch = new TranslationMatch();
translationMatch.setConcept(
new Coding()
.setCode(element.getCode())
.setSystem(element.getSystem())
.setVersion(element.getSystemVersion())
.setDisplay(element.getDisplay())
);
translationMatch.setSource(new UriType(element.getConceptMapUrl()));
retVal.addMatch(translationMatch);
}
}
}
return retVal;
}
@Override
protected ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
ConceptMap conceptMap = (ConceptMap) theResource;
if (conceptMap != null && isNotBlank(conceptMap.getUrl())) {
// Convert from DSTU3 to R4
try {
myHapiTerminologySvc.storeTermConceptMapAndChildren(retVal, VersionConvertor_30_40.convertConceptMap(conceptMap));
} catch (FHIRException fe) {
throw new InternalErrorException(fe);
}
}
return retVal;
}
}

View File

@ -0,0 +1,167 @@
package ca.uhn.fhir.jpa.dao.r4;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2018 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.jpa.dao.IFhirResourceDaoConceptMap;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElement;
import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElementTarget;
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
import ca.uhn.fhir.jpa.term.TranslationMatch;
import ca.uhn.fhir.jpa.term.TranslationRequest;
import ca.uhn.fhir.jpa.term.TranslationResult;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.*;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class FhirResourceDaoConceptMapR4 extends FhirResourceDaoR4<ConceptMap> implements IFhirResourceDaoConceptMap<ConceptMap> {
@Autowired
private IHapiTerminologySvc myHapiTerminologySvc;
@Override
public TranslationResult translate(TranslationRequest theTranslationRequest, RequestDetails theRequestDetails) {
if (theTranslationRequest.hasReverse() && theTranslationRequest.getReverseAsBoolean()) {
return buildReverseTranslationResult(myHapiTerminologySvc.translateWithReverse(theTranslationRequest));
}
return buildTranslationResult(myHapiTerminologySvc.translate(theTranslationRequest));
}
private TranslationResult buildTranslationResult(List<TermConceptMapGroupElementTarget> theTargets) {
TranslationResult retVal = new TranslationResult();
String msg;
if (theTargets.isEmpty()) {
retVal.setResult(new BooleanType(false));
msg = getContext().getLocalizer().getMessage(
FhirResourceDaoConceptMapR4.class,
"noMatchesFound");
retVal.setMessage(new StringType(msg));
} else {
retVal.setResult(new BooleanType(true));
msg = getContext().getLocalizer().getMessage(
FhirResourceDaoConceptMapR4.class,
"matchesFound");
retVal.setMessage(new StringType(msg));
TranslationMatch translationMatch;
Set<TermConceptMapGroupElementTarget> targetsToReturn = new HashSet<>();
for (TermConceptMapGroupElementTarget target : theTargets) {
if (targetsToReturn.add(target)) {
translationMatch = new TranslationMatch();
translationMatch.setEquivalence(new CodeType(target.getEquivalence().toCode()));
translationMatch.setConcept(
new Coding()
.setCode(target.getCode())
.setSystem(target.getSystem())
.setVersion(target.getSystemVersion())
.setDisplay(target.getDisplay())
);
translationMatch.setSource(new UriType(target.getConceptMapUrl()));
retVal.addMatch(translationMatch);
}
}
}
return retVal;
}
private TranslationResult buildReverseTranslationResult(List<TermConceptMapGroupElement> theElements) {
TranslationResult retVal = new TranslationResult();
String msg;
if (theElements.isEmpty()) {
retVal.setResult(new BooleanType(false));
msg = getContext().getLocalizer().getMessage(
FhirResourceDaoConceptMapR4.class,
"noMatchesFound");
retVal.setMessage(new StringType(msg));
} else {
retVal.setResult(new BooleanType(true));
msg = getContext().getLocalizer().getMessage(
FhirResourceDaoConceptMapR4.class,
"matchesFound");
retVal.setMessage(new StringType(msg));
TranslationMatch translationMatch;
Set<TermConceptMapGroupElement> elementsToReturn = new HashSet<>();
for (TermConceptMapGroupElement element : theElements) {
if (elementsToReturn.add(element)) {
translationMatch = new TranslationMatch();
translationMatch.setConcept(
new Coding()
.setCode(element.getCode())
.setSystem(element.getSystem())
.setVersion(element.getSystemVersion())
.setDisplay(element.getDisplay())
);
translationMatch.setSource(new UriType(element.getConceptMapUrl()));
retVal.addMatch(translationMatch);
}
}
}
return retVal;
}
@Override
protected ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
ConceptMap conceptMap = (ConceptMap) theResource;
if (conceptMap != null && isNotBlank(conceptMap.getUrl())) {
myHapiTerminologySvc.storeTermConceptMapAndChildren(retVal, conceptMap);
}
return retVal;
}
}

View File

@ -11,7 +11,6 @@ import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.search.annotations.*; import org.hibernate.search.annotations.*;
import org.hl7.fhir.r4.model.Coding; import org.hl7.fhir.r4.model.Coding;
import org.springframework.validation.ValidationUtils;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.persistence.*; import javax.persistence.*;
@ -49,7 +48,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
@Index(name = "IDX_CONCEPT_INDEXSTATUS", columnList = "INDEX_STATUS") @Index(name = "IDX_CONCEPT_INDEXSTATUS", columnList = "INDEX_STATUS")
}) })
public class TermConcept implements Serializable { public class TermConcept implements Serializable {
private static final int MAX_DESC_LENGTH = 400; protected static final int MAX_DESC_LENGTH = 400;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TermConcept.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TermConcept.class);
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -0,0 +1,105 @@
package ca.uhn.fhir.jpa.entity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.persistence.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "TRM_CONCEPT_MAP", uniqueConstraints = {
@UniqueConstraint(name = "IDX_CONCEPT_MAP_URL", columnNames = {"URL"})
})
public class TermConceptMap implements Serializable {
@Id()
@SequenceGenerator(name = "SEQ_CONCEPT_MAP_PID", sequenceName = "SEQ_CONCEPT_MAP_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_MAP_PID")
@Column(name = "PID")
private Long myId;
@OneToOne()
@JoinColumn(name = "RES_ID", referencedColumnName = "RES_ID", nullable = false, updatable = false, foreignKey = @ForeignKey(name = "FK_TRMCONCEPTMAP_RES"))
private ResourceTable myResource;
@Column(name = "RES_ID", insertable = false, updatable = false)
private Long myResourcePid;
@Column(name = "SOURCE_URL", nullable = false, length = 200)
private String mySource;
@Column(name = "TARGET_URL", nullable = false, length = 200)
private String myTarget;
@Column(name = "URL", length = 200)
private String myUrl;
@OneToMany(mappedBy = "myConceptMap")
private List<TermConceptMapGroup> myConceptMapGroups;
public List<TermConceptMapGroup> getConceptMapGroups() {
if (myConceptMapGroups == null) {
myConceptMapGroups = new ArrayList<>();
}
return myConceptMapGroups;
}
public Long getId() {
return myId;
}
public ResourceTable getResource() {
return myResource;
}
public void setResource(ResourceTable resource) {
myResource = resource;
}
public Long getResourcePid() {
return myResourcePid;
}
public void setResourcePid(Long resourcePid) {
myResourcePid = resourcePid;
}
public String getSource() {
return mySource;
}
public void setSource(String source) {
mySource = source;
}
public String getTarget() {
return myTarget;
}
public void setTarget(String target) {
myTarget = target;
}
public String getUrl() {
return myUrl;
}
public void setUrl(String theUrl) {
myUrl = theUrl;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("myId", myId)
.append("myResource", myResource.toString())
.append("myResourcePid", myResourcePid)
.append("mySource", mySource)
.append("myTarget", myTarget)
.append("myUrl", myUrl)
.append("myConceptMapGroups - size", myConceptMapGroups.size())
.toString();
}
}

View File

@ -0,0 +1,131 @@
package ca.uhn.fhir.jpa.entity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.persistence.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "TRM_CONCEPT_MAP_GROUP")
public class TermConceptMapGroup implements Serializable {
@Id()
@SequenceGenerator(name = "SEQ_CONCEPT_MAP_GROUP_PID", sequenceName = "SEQ_CONCEPT_MAP_GROUP_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_MAP_GROUP_PID")
@Column(name = "PID")
private Long myId;
@ManyToOne()
@JoinColumn(name = "CONCEPT_MAP_PID", nullable = false, referencedColumnName = "PID", foreignKey=@ForeignKey(name="FK_TCMGROUP_CONCEPTMAP"))
private TermConceptMap myConceptMap;
@Column(name = "SOURCE_URL", nullable = false, length = 200)
private String mySource;
@Column(name = "SOURCE_VERSION", length = 50)
private String mySourceVersion;
@Column(name = "TARGET_URL", nullable = false, length = 200)
private String myTarget;
@Column(name = "TARGET_VERSION", length = 50)
private String myTargetVersion;
@OneToMany(mappedBy = "myConceptMapGroup")
private List<TermConceptMapGroupElement> myConceptMapGroupElements;
private String myConceptMapUrl;
private String mySourceValueSet;
private String myTargetValueSet;
public TermConceptMap getConceptMap() {
return myConceptMap;
}
public void setConceptMap(TermConceptMap theTermConceptMap) {
myConceptMap = theTermConceptMap;
}
public List<TermConceptMapGroupElement> getConceptMapGroupElements() {
if (myConceptMapGroupElements == null) {
myConceptMapGroupElements = new ArrayList<>();
}
return myConceptMapGroupElements;
}
public String getConceptMapUrl() {
if (myConceptMapUrl == null) {
myConceptMapUrl = getConceptMap().getUrl();
}
return myConceptMapUrl;
}
public Long getId() {
return myId;
}
public String getSource() {
return mySource;
}
public void setSource(String theSource) {
this.mySource = theSource;
}
public String getSourceValueSet() {
if (mySourceValueSet == null) {
mySourceValueSet = getConceptMap().getSource();
}
return mySourceValueSet;
}
public String getSourceVersion() {
return mySourceVersion;
}
public void setSourceVersion(String theSourceVersion) {
mySourceVersion = theSourceVersion;
}
public String getTarget() {
return myTarget;
}
public void setTarget(String theTarget) {
this.myTarget = theTarget;
}
public String getTargetValueSet() {
if (myTargetValueSet == null) {
myTargetValueSet = getConceptMap().getTarget();
}
return myTargetValueSet;
}
public String getTargetVersion() {
return myTargetVersion;
}
public void setTargetVersion(String theTargetVersion) {
myTargetVersion = theTargetVersion;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("myId", myId)
.append("myConceptMap - id", myConceptMap.getId())
.append("mySource", mySource)
.append("mySourceVersion", mySourceVersion)
.append("myTarget", myTarget)
.append("myTargetVersion", myTargetVersion)
.append("myConceptMapGroupElements - size", myConceptMapGroupElements.size())
.append("myConceptMapUrl", this.getConceptMapUrl())
.append("mySourceValueSet", this.getSourceValueSet())
.append("myTargetValueSet", this.getTargetValueSet())
.toString();
}
}

View File

@ -0,0 +1,144 @@
package ca.uhn.fhir.jpa.entity;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.persistence.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "TRM_CONCEPT_MAP_GRP_ELEMENT", indexes = {
@Index(name = "IDX_CNCPT_MAP_GRP_CD", columnList = "SOURCE_CODE")
})
public class TermConceptMapGroupElement implements Serializable {
@Id()
@SequenceGenerator(name = "SEQ_CONCEPT_MAP_GRP_ELM_PID", sequenceName = "SEQ_CONCEPT_MAP_GRP_ELM_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_MAP_GRP_ELM_PID")
@Column(name = "PID")
private Long myId;
@ManyToOne()
@JoinColumn(name = "CONCEPT_MAP_GROUP_PID", nullable = false, referencedColumnName = "PID", foreignKey=@ForeignKey(name="FK_TCMGELEMENT_GROUP"))
private TermConceptMapGroup myConceptMapGroup;
@Column(name = "SOURCE_CODE", nullable = false, length = 50)
private String myCode;
@Column(name = "SOURCE_DISPLAY", length = TermConcept.MAX_DESC_LENGTH)
private String myDisplay;
@OneToMany(mappedBy = "myConceptMapGroupElement")
private List<TermConceptMapGroupElementTarget> myConceptMapGroupElementTargets;
private String myConceptMapUrl;
private String mySystem;
private String mySystemVersion;
private String myValueSet;
public String getCode() {
return myCode;
}
public void setCode(String theCode) {
myCode = theCode;
}
public TermConceptMapGroup getConceptMapGroup() {
return myConceptMapGroup;
}
public void setConceptMapGroup(TermConceptMapGroup theTermConceptMapGroup) {
myConceptMapGroup = theTermConceptMapGroup;
}
public List<TermConceptMapGroupElementTarget> getConceptMapGroupElementTargets() {
if (myConceptMapGroupElementTargets == null) {
myConceptMapGroupElementTargets = new ArrayList<>();
}
return myConceptMapGroupElementTargets;
}
public String getConceptMapUrl() {
if (myConceptMapUrl == null) {
myConceptMapUrl = getConceptMapGroup().getConceptMap().getUrl();
}
return myConceptMapUrl;
}
public String getDisplay() {
return myDisplay;
}
public void setDisplay(String theDisplay) {
myDisplay = theDisplay;
}
public Long getId() {
return myId;
}
public String getSystem() {
if (mySystem == null) {
mySystem = getConceptMapGroup().getSource();
}
return mySystem;
}
public String getSystemVersion() {
if (mySystemVersion == null) {
mySystemVersion = getConceptMapGroup().getSourceVersion();
}
return mySystemVersion;
}
public String getValueSet() {
if (myValueSet == null) {
myValueSet = getConceptMapGroup().getSourceValueSet();
}
return myValueSet;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TermConceptMapGroupElement)) return false;
TermConceptMapGroupElement that = (TermConceptMapGroupElement) o;
return new EqualsBuilder()
.append(getCode(), that.getCode())
.append(getSystem(), that.getSystem())
.append(getSystemVersion(), that.getSystemVersion())
.isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder(17, 37)
.append(getCode())
.append(getSystem())
.append(getSystemVersion())
.toHashCode();
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("myId", myId)
.append("myConceptMapGroup - id", myConceptMapGroup.getId())
.append("myCode", myCode)
.append("myDisplay", myDisplay)
.append("myConceptMapGroupElementTargets - size", myConceptMapGroupElementTargets.size())
.append("myConceptMapUrl", this.getConceptMapUrl())
.append("mySystem", this.getSystem())
.append("mySystemVersion", this.getSystemVersion())
.append("myValueSet", this.getValueSet())
.toString();
}
}

View File

@ -0,0 +1,146 @@
package ca.uhn.fhir.jpa.entity;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name = "TRM_CONCEPT_MAP_GRP_ELM_TGT", indexes = {
@Index(name = "IDX_CNCPT_MP_GRP_ELM_TGT_CD", columnList = "TARGET_CODE")
})
public class TermConceptMapGroupElementTarget implements Serializable {
@Id()
@SequenceGenerator(name = "SEQ_CNCPT_MAP_GRP_ELM_TGT_PID", sequenceName = "SEQ_CNCPT_MAP_GRP_ELM_TGT_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CNCPT_MAP_GRP_ELM_TGT_PID")
@Column(name = "PID")
private Long myId;
@ManyToOne()
@JoinColumn(name = "CONCEPT_MAP_GRP_ELM_PID", nullable = false, referencedColumnName = "PID", foreignKey=@ForeignKey(name="FK_TCMGETARGET_ELEMENT"))
private TermConceptMapGroupElement myConceptMapGroupElement;
@Column(name = "TARGET_CODE", nullable = false, length = 50)
private String myCode;
@Column(name = "TARGET_DISPLAY", length = TermConcept.MAX_DESC_LENGTH)
private String myDisplay;
@Enumerated(EnumType.STRING)
@Column(name = "TARGET_EQUIVALENCE", length = 50)
private ConceptMapEquivalence myEquivalence;
private String myConceptMapUrl;
private String mySystem;
private String mySystemVersion;
private String myValueSet;
public String getCode() {
return myCode;
}
public void setCode(String theCode) {
myCode = theCode;
}
public TermConceptMapGroupElement getConceptMapGroupElement() {
return myConceptMapGroupElement;
}
public void setConceptMapGroupElement(TermConceptMapGroupElement theTermConceptMapGroupElement) {
myConceptMapGroupElement = theTermConceptMapGroupElement;
}
public String getConceptMapUrl() {
if (myConceptMapUrl == null) {
myConceptMapUrl = getConceptMapGroupElement().getConceptMapGroup().getConceptMap().getUrl();
}
return myConceptMapUrl;
}
public String getDisplay() {
return myDisplay;
}
public void setDisplay(String theDisplay) {
myDisplay = theDisplay;
}
public ConceptMapEquivalence getEquivalence() {
return myEquivalence;
}
public void setEquivalence(ConceptMapEquivalence theEquivalence) {
myEquivalence = theEquivalence;
}
public Long getId() {
return myId;
}
public String getSystem() {
if (mySystem == null) {
mySystem = getConceptMapGroupElement().getConceptMapGroup().getTarget();
}
return mySystem;
}
public String getSystemVersion() {
if (mySystemVersion == null) {
mySystemVersion = getConceptMapGroupElement().getConceptMapGroup().getTargetVersion();
}
return mySystemVersion;
}
public String getValueSet() {
if (myValueSet == null) {
myValueSet = getConceptMapGroupElement().getConceptMapGroup().getTargetValueSet();
}
return myValueSet;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TermConceptMapGroupElementTarget)) return false;
TermConceptMapGroupElementTarget that = (TermConceptMapGroupElementTarget) o;
return new EqualsBuilder()
.append(getCode(), that.getCode())
.append(getEquivalence(), that.getEquivalence())
.append(getSystem(), that.getSystem())
.append(getSystemVersion(), that.getSystemVersion())
.isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder(17, 37)
.append(getCode())
.append(getEquivalence())
.append(getSystem())
.append(getSystemVersion())
.toHashCode();
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("myId", myId)
.append("myConceptMapGroupElement - id", myConceptMapGroupElement.getId())
.append("myCode", myCode)
.append("myDisplay", myDisplay)
.append("myEquivalence", myEquivalence.toCode())
.append("myConceptMapUrl", this.getConceptMapUrl())
.append("mySystem", this.getSystem())
.append("mySystemVersion", this.getSystemVersion())
.append("myValueSet", this.getValueSet())
.toString();
}
}

View File

@ -0,0 +1,153 @@
package ca.uhn.fhir.jpa.provider.dstu3;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2018 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.jpa.dao.IFhirResourceDaoConceptMap;
import ca.uhn.fhir.jpa.term.TranslationRequest;
import ca.uhn.fhir.jpa.term.TranslationResult;
import ca.uhn.fhir.jpa.util.JpaConstants;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.convertors.VersionConvertor_30_40;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.exceptions.FHIRException;
import javax.servlet.http.HttpServletRequest;
public class BaseJpaResourceProviderConceptMapDstu3 extends JpaResourceProviderDstu3<ConceptMap> {
@Operation(name = JpaConstants.OPERATION_TRANSLATE, idempotent = true, returnParameters = {
@OperationParam(name = "result", type = BooleanType.class, min = 1, max = 1),
@OperationParam(name = "message", type = StringType.class, min = 0, max = 1),
})
public Parameters translate(
HttpServletRequest theServletRequest,
@IdParam(optional = true) IdType theId,
@OperationParam(name = "code", min = 0, max = 1) CodeType theSourceCode,
@OperationParam(name = "system", min = 0, max = 1) UriType theSourceCodeSystem,
@OperationParam(name = "version", min = 0, max = 1) StringType theSourceCodeSystemVersion,
@OperationParam(name = "source", min = 0, max = 1) UriType theSourceValueSet,
@OperationParam(name = "coding", min = 0, max = 1) Coding theSourceCoding,
@OperationParam(name = "codeableConcept", min = 0, max = 1) CodeableConcept theSourceCodeableConcept,
@OperationParam(name = "target", min = 0, max = 1) UriType theTargetValueSet,
@OperationParam(name = "targetsystem", min = 0, max = 1) UriType theTargetCodeSystem,
@OperationParam(name = "reverse", min = 0, max = 1) BooleanType theReverse,
RequestDetails theRequestDetails
) {
boolean haveSourceCode = theSourceCode != null
&& theSourceCode.hasValue();
boolean haveSourceCodeSystem = theSourceCodeSystem != null
&& theSourceCodeSystem.hasValue();
boolean haveSourceCodeSystemVersion = theSourceCodeSystemVersion != null
&& theSourceCodeSystemVersion.hasValue();
boolean haveSourceValueSet = theSourceValueSet != null
&& theSourceValueSet.hasValue();
boolean haveSourceCoding = theSourceCoding != null
&& theSourceCoding.hasCode();
boolean haveSourceCodeableConcept= theSourceCodeableConcept != null
&& theSourceCodeableConcept.hasCoding()
&& theSourceCodeableConcept.getCodingFirstRep().hasCode();
boolean haveTargetValueSet = theTargetValueSet != null
&& theTargetValueSet.hasValue();
boolean haveTargetCodeSystem = theTargetCodeSystem != null
&& theTargetCodeSystem.hasValue();
boolean haveReverse = theReverse != null;
boolean haveId = theId != null && theId.hasIdPart();
// <editor-fold desc="Filters">
if ((!haveSourceCode && !haveSourceCoding && !haveSourceCodeableConcept)
|| moreThanOneTrue(haveSourceCode, haveSourceCoding, haveSourceCodeableConcept)) {
throw new InvalidRequestException("One (and only one) of the in parameters (code, coding, codeableConcept) must be provided, to identify the code that is to be translated.");
}
TranslationRequest translationRequest = new TranslationRequest();
try {
// Convert from DSTU3 to R4
if (haveSourceCode) {
translationRequest.getCodeableConcept().addCoding().setCodeElement(VersionConvertor_30_40.convertCode(theSourceCode));
if (haveSourceCodeSystem) {
translationRequest.getCodeableConcept().getCodingFirstRep().setSystemElement(VersionConvertor_30_40.convertUri(theSourceCodeSystem));
}
if (haveSourceCodeSystemVersion) {
translationRequest.getCodeableConcept().getCodingFirstRep().setVersionElement(VersionConvertor_30_40.convertString(theSourceCodeSystemVersion));
}
} else if (haveSourceCoding) {
translationRequest.getCodeableConcept().addCoding(VersionConvertor_30_40.convertCoding(theSourceCoding));
} else {
translationRequest.setCodeableConcept(VersionConvertor_30_40.convertCodeableConcept(theSourceCodeableConcept));
}
if (haveSourceValueSet) {
translationRequest.setSource(VersionConvertor_30_40.convertUri(theSourceValueSet));
}
if (haveTargetValueSet) {
translationRequest.setTarget(VersionConvertor_30_40.convertUri(theTargetValueSet));
}
if (haveTargetCodeSystem) {
translationRequest.setTargetSystem(VersionConvertor_30_40.convertUri(theTargetCodeSystem));
}
if (haveReverse) {
translationRequest.setReverse(VersionConvertor_30_40.convertBoolean(theReverse));
}
if (haveId) {
translationRequest.setResourceId(theId.getIdPartAsLong());
}
} catch (FHIRException fe) {
throw new InternalErrorException(fe);
}
startRequest(theServletRequest);
try {
IFhirResourceDaoConceptMap<ConceptMap> dao = (IFhirResourceDaoConceptMap<ConceptMap>) getDao();
TranslationResult result = dao.translate(translationRequest, theRequestDetails);
// Convert from R4 to DSTU3
return VersionConvertor_30_40.convertParameters(result.toParameters());
} catch (FHIRException fe) {
throw new InternalErrorException(fe);
} finally {
endRequest(theServletRequest);
}
}
private static boolean moreThanOneTrue(boolean... theBooleans) {
boolean haveOne = false;
for (boolean next : theBooleans) {
if (next) {
if (haveOne) {
return true;
} else {
haveOne = true;
}
}
}
return false;
}
}

View File

@ -0,0 +1,142 @@
package ca.uhn.fhir.jpa.provider.r4;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2018 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.jpa.dao.IFhirResourceDaoConceptMap;
import ca.uhn.fhir.jpa.term.TranslationRequest;
import ca.uhn.fhir.jpa.term.TranslationResult;
import ca.uhn.fhir.jpa.util.JpaConstants;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.r4.model.*;
import javax.servlet.http.HttpServletRequest;
public class BaseJpaResourceProviderConceptMapR4 extends JpaResourceProviderR4<ConceptMap> {
@Operation(name = JpaConstants.OPERATION_TRANSLATE, idempotent = true, returnParameters = {
@OperationParam(name = "result", type = BooleanType.class, min = 1, max = 1),
@OperationParam(name = "message", type = StringType.class, min = 0, max = 1),
})
public Parameters translate(
HttpServletRequest theServletRequest,
@IdParam(optional = true) IdType theId,
@OperationParam(name = "code", min = 0, max = 1) CodeType theSourceCode,
@OperationParam(name = "system", min = 0, max = 1) UriType theSourceCodeSystem,
@OperationParam(name = "version", min = 0, max = 1) StringType theSourceCodeSystemVersion,
@OperationParam(name = "source", min = 0, max = 1) UriType theSourceValueSet,
@OperationParam(name = "coding", min = 0, max = 1) Coding theSourceCoding,
@OperationParam(name = "codeableConcept", min = 0, max = 1) CodeableConcept theSourceCodeableConcept,
@OperationParam(name = "target", min = 0, max = 1) UriType theTargetValueSet,
@OperationParam(name = "targetsystem", min = 0, max = 1) UriType theTargetCodeSystem,
@OperationParam(name = "reverse", min = 0, max = 1) BooleanType theReverse,
RequestDetails theRequestDetails
) {
boolean haveSourceCode = theSourceCode != null
&& theSourceCode.hasCode();
boolean haveSourceCodeSystem = theSourceCodeSystem != null
&& theSourceCodeSystem.hasValue();
boolean haveSourceCodeSystemVersion = theSourceCodeSystemVersion != null
&& theSourceCodeSystemVersion.hasValue();
boolean haveSourceValueSet = theSourceValueSet != null
&& theSourceValueSet.hasValue();
boolean haveSourceCoding = theSourceCoding != null
&& theSourceCoding.hasCode();
boolean haveSourceCodeableConcept= theSourceCodeableConcept != null
&& theSourceCodeableConcept.hasCoding()
&& theSourceCodeableConcept.getCodingFirstRep().hasCode();
boolean haveTargetValueSet = theTargetValueSet != null
&& theTargetValueSet.hasValue();
boolean haveTargetCodeSystem = theTargetCodeSystem != null
&& theTargetCodeSystem.hasValue();
boolean haveReverse = theReverse != null;
boolean haveId = theId != null && theId.hasIdPart();
// <editor-fold desc="Filters">
if ((!haveSourceCode && !haveSourceCoding && !haveSourceCodeableConcept)
|| moreThanOneTrue(haveSourceCode, haveSourceCoding, haveSourceCodeableConcept)) {
throw new InvalidRequestException("One (and only one) of the in parameters (code, coding, codeableConcept) must be provided, to identify the code that is to be translated.");
}
TranslationRequest translationRequest = new TranslationRequest();
if (haveSourceCode) {
translationRequest.getCodeableConcept().addCoding().setCodeElement(theSourceCode);
if (haveSourceCodeSystem) {
translationRequest.getCodeableConcept().getCodingFirstRep().setSystemElement(theSourceCodeSystem);
}
if (haveSourceCodeSystemVersion) {
translationRequest.getCodeableConcept().getCodingFirstRep().setVersionElement(theSourceCodeSystemVersion);
}
} else if (haveSourceCoding) {
translationRequest.getCodeableConcept().addCoding(theSourceCoding);
} else {
translationRequest.setCodeableConcept(theSourceCodeableConcept);
}
if (haveSourceValueSet) {
translationRequest.setSource(theSourceValueSet);
}
if (haveTargetValueSet) {
translationRequest.setTarget(theTargetValueSet);
}
if (haveTargetCodeSystem) {
translationRequest.setTargetSystem(theTargetCodeSystem);
}
if (haveReverse) {
translationRequest.setReverse(theReverse);
}
if (haveId) {
translationRequest.setResourceId(theId.getIdPartAsLong());
}
startRequest(theServletRequest);
try {
IFhirResourceDaoConceptMap<ConceptMap> dao = (IFhirResourceDaoConceptMap<ConceptMap>) getDao();
TranslationResult result = dao.translate(translationRequest, theRequestDetails);
return result.toParameters();
} finally {
endRequest(theServletRequest);
}
}
private static boolean moreThanOneTrue(boolean... theBooleans) {
boolean haveOne = false;
for (boolean next : theBooleans) {
if (next) {
if (haveOne) {
return true;
} else {
haveOne = true;
}
}
}
return false;
}
}

View File

@ -27,24 +27,32 @@ import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.jpa.dao.data.*; import ca.uhn.fhir.jpa.dao.data.*;
import ca.uhn.fhir.jpa.entity.*; import ca.uhn.fhir.jpa.entity.*;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum; import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
import ca.uhn.fhir.jpa.util.ScrollableResultsIterator;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.ObjectUtil; import ca.uhn.fhir.util.ObjectUtil;
import ca.uhn.fhir.util.StopWatch; import ca.uhn.fhir.util.StopWatch;
import ca.uhn.fhir.util.ValidateUtil; import ca.uhn.fhir.util.ValidateUtil;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Stopwatch; import com.google.common.base.Stopwatch;
import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ArrayListMultimap;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.time.DateUtils; import org.apache.commons.lang3.time.DateUtils;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.search.jpa.FullTextEntityManager; import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.FullTextQuery; import org.hibernate.search.jpa.FullTextQuery;
import org.hibernate.search.query.dsl.BooleanJunction; import org.hibernate.search.query.dsl.BooleanJunction;
import org.hibernate.search.query.dsl.QueryBuilder; import org.hibernate.search.query.dsl.QueryBuilder;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.ConceptMap; import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.ValueSet; import org.hl7.fhir.r4.model.ValueSet;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -58,9 +66,12 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.support.TransactionTemplate;
import javax.annotation.PostConstruct;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext; import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType; import javax.persistence.PersistenceContextType;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.*;
import java.util.*; import java.util.*;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -69,14 +80,26 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc { public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc {
public static final int DEFAULT_FETCH_SIZE = 250;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiTerminologySvcImpl.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiTerminologySvcImpl.class);
private static final Object PLACEHOLDER_OBJECT = new Object(); private static final Object PLACEHOLDER_OBJECT = new Object();
private static boolean ourForceSaveDeferredAlwaysForUnitTest; private static boolean ourForceSaveDeferredAlwaysForUnitTest;
private static boolean ourLastResultsFromTranslationCache; // For testing.
private static boolean ourLastResultsFromTranslationWithReverseCache; // For testing.
@Autowired @Autowired
protected ITermCodeSystemDao myCodeSystemDao; protected ITermCodeSystemDao myCodeSystemDao;
@Autowired @Autowired
protected ITermConceptDao myConceptDao; protected ITermConceptDao myConceptDao;
@Autowired @Autowired
protected ITermConceptMapDao myConceptMapDao;
@Autowired
protected ITermConceptMapGroupDao myConceptMapGroupDao;
@Autowired
protected ITermConceptMapGroupElementDao myConceptMapGroupElementDao;
@Autowired
protected ITermConceptMapGroupElementTargetDao myConceptMapGroupElementTargetDao;
@Autowired
protected ITermConceptPropertyDao myConceptPropertyDao; protected ITermConceptPropertyDao myConceptPropertyDao;
@Autowired @Autowired
protected ITermConceptDesignationDao myConceptDesignationDao; protected ITermConceptDesignationDao myConceptDesignationDao;
@ -102,6 +125,12 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
@Autowired(required = false) @Autowired(required = false)
private IFhirResourceDaoCodeSystem<?, ?, ?> myCodeSystemResourceDao; private IFhirResourceDaoCodeSystem<?, ?, ?> myCodeSystemResourceDao;
private Cache<TranslationQuery, List<TermConceptMapGroupElementTarget>> myTranslationCache;
private Cache<TranslationQuery, List<TermConceptMapGroupElement>> myTranslationWithReverseCache;
private int myFetchSize = DEFAULT_FETCH_SIZE;
private void addCodeIfNotAlreadyAdded(String theCodeSystem, ValueSet.ValueSetExpansionComponent theExpansionComponent, Set<String> theAddedCodes, TermConcept theConcept) { private void addCodeIfNotAlreadyAdded(String theCodeSystem, ValueSet.ValueSetExpansionComponent theExpansionComponent, Set<String> theAddedCodes, TermConcept theConcept) {
if (theAddedCodes.add(theConcept.getCode())) { if (theAddedCodes.add(theConcept.getCode())) {
ValueSet.ValueSetExpansionContainsComponent contains = theExpansionComponent.addContains(); ValueSet.ValueSetExpansionContainsComponent contains = theExpansionComponent.addContains();
@ -160,6 +189,23 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
return retVal; return retVal;
} }
@PostConstruct
public void buildTranslationCaches() {
Long timeout = myDaoConfig.getTranslationCachesExpireAfterWriteInMinutes();
myTranslationCache =
Caffeine.newBuilder()
.maximumSize(10000)
.expireAfterWrite(timeout, TimeUnit.MINUTES)
.build();
myTranslationWithReverseCache =
Caffeine.newBuilder()
.maximumSize(10000)
.expireAfterWrite(timeout, TimeUnit.MINUTES)
.build();
}
protected abstract IIdType createOrUpdateCodeSystem(CodeSystem theCodeSystemResource); protected abstract IIdType createOrUpdateCodeSystem(CodeSystem theCodeSystemResource);
protected abstract void createOrUpdateConceptMap(ConceptMap theNextConceptMap); protected abstract void createOrUpdateConceptMap(ConceptMap theNextConceptMap);
@ -869,6 +915,112 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
return csId; return csId;
} }
@Override
@Transactional
public void storeTermConceptMapAndChildren(ResourceTable theResourceTable, ConceptMap theConceptMap) {
ourLog.info("Storing TermConceptMap...");
ValidateUtil.isTrueOrThrowInvalidRequest(theResourceTable != null, "No resource supplied.");
ValidateUtil.isNotBlankOrThrowInvalidRequest(theConceptMap.getUrl(), "No URL supplied.");
TermConceptMap termConceptMap = new TermConceptMap();
termConceptMap.setResource(theResourceTable);
termConceptMap.setUrl(theConceptMap.getUrl());
// Get existing entity so it can be deleted.
Optional<TermConceptMap> optionalExistingTermConceptMapById = myConceptMapDao.findTermConceptMapByResourcePid(termConceptMap.getResourcePid());
/*
* For now we always delete old versions. At some point, it would be nice to allow configuration to keep old versions.
*/
if (optionalExistingTermConceptMapById.isPresent()) {
Long id = optionalExistingTermConceptMapById.get().getId();
ourLog.info("Deleting existing TermConceptMap {} and its children...", id);
myConceptMapGroupElementTargetDao.deleteTermConceptMapGroupElementTargetById(id);
myConceptMapGroupElementDao.deleteTermConceptMapGroupElementById(id);
myConceptMapGroupDao.deleteTermConceptMapGroupById(id);
myConceptMapDao.deleteTermConceptMapById(id);
ourLog.info("Done deleting existing TermConceptMap {} and its children.", id);
ourLog.info("Flushing...");
myConceptMapGroupElementTargetDao.flush();
myConceptMapGroupElementDao.flush();
myConceptMapGroupDao.flush();
myConceptMapDao.flush();
ourLog.info("Done flushing.");
}
/*
* Do the upload.
*/
String conceptMapUrl = termConceptMap.getUrl();
Optional<TermConceptMap> optionalExistingTermConceptMapByUrl = myConceptMapDao.findTermConceptMapByUrl(conceptMapUrl);
if (!optionalExistingTermConceptMapByUrl.isPresent()) {
try {
String source = theConceptMap.getSourceUriType().getValueAsString();
if (isNotBlank(source)) {
termConceptMap.setSource(source);
}
String target = theConceptMap.getTargetUriType().getValueAsString();
if (isNotBlank(target)) {
termConceptMap.setTarget(target);
}
} catch (FHIRException fe) {
throw new InternalErrorException(fe);
}
myConceptMapDao.save(termConceptMap);
if (theConceptMap.hasGroup()) {
TermConceptMapGroup termConceptMapGroup;
for (ConceptMap.ConceptMapGroupComponent group : theConceptMap.getGroup()) {
termConceptMapGroup = new TermConceptMapGroup();
termConceptMapGroup.setConceptMap(termConceptMap);
termConceptMapGroup.setSource(group.getSource());
termConceptMapGroup.setSourceVersion(group.getSourceVersion());
termConceptMapGroup.setTarget(group.getTarget());
termConceptMapGroup.setTargetVersion(group.getTargetVersion());
myConceptMapGroupDao.save(termConceptMapGroup);
if (group.hasElement()) {
TermConceptMapGroupElement termConceptMapGroupElement;
for (ConceptMap.SourceElementComponent element : group.getElement()) {
termConceptMapGroupElement = new TermConceptMapGroupElement();
termConceptMapGroupElement.setConceptMapGroup(termConceptMapGroup);
termConceptMapGroupElement.setCode(element.getCode());
termConceptMapGroupElement.setDisplay(element.getDisplay());
myConceptMapGroupElementDao.save(termConceptMapGroupElement);
if (element.hasTarget()) {
TermConceptMapGroupElementTarget termConceptMapGroupElementTarget;
for (ConceptMap.TargetElementComponent target : element.getTarget()) {
termConceptMapGroupElementTarget = new TermConceptMapGroupElementTarget();
termConceptMapGroupElementTarget.setConceptMapGroupElement(termConceptMapGroupElement);
termConceptMapGroupElementTarget.setCode(target.getCode());
termConceptMapGroupElementTarget.setDisplay(target.getDisplay());
termConceptMapGroupElementTarget.setEquivalence(target.getEquivalence());
myConceptMapGroupElementTargetDao.saveAndFlush(termConceptMapGroupElementTarget);
}
}
}
}
}
}
} else {
TermConceptMap existingTermConceptMap = optionalExistingTermConceptMapByUrl.get();
String msg = myContext.getLocalizer().getMessage(
BaseHapiTerminologySvcImpl.class,
"cannotCreateDuplicateConceptMapUrl",
conceptMapUrl,
existingTermConceptMap.getResourcePid());
throw new UnprocessableEntityException(msg);
}
ourLog.info("Done storing TermConceptMap.");
}
@Override @Override
public boolean supportsSystem(String theSystem) { public boolean supportsSystem(String theSystem) {
TermCodeSystem cs = getCodeSystem(theSystem); TermCodeSystem cs = getCodeSystem(theSystem);
@ -883,6 +1035,166 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
return retVal; return retVal;
} }
@Override
public List<TermConceptMapGroupElementTarget> translate(TranslationRequest theTranslationRequest) {
List<TermConceptMapGroupElementTarget> retVal = new ArrayList<>();
CriteriaBuilder criteriaBuilder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<TermConceptMapGroupElementTarget> query = criteriaBuilder.createQuery(TermConceptMapGroupElementTarget.class);
Root<TermConceptMapGroupElementTarget> root = query.from(TermConceptMapGroupElementTarget.class);
Join<TermConceptMapGroupElementTarget, TermConceptMapGroupElement> elementJoin = root.join("myConceptMapGroupElement");
Join<TermConceptMapGroupElement, TermConceptMapGroup> groupJoin = elementJoin.join("myConceptMapGroup");
Join<TermConceptMapGroup, TermConceptMap> conceptMapJoin = groupJoin.join("myConceptMap");
List<TranslationQuery> translationQueries = theTranslationRequest.getTranslationQueries();
List<TermConceptMapGroupElementTarget> cachedTargets;
ArrayList<Predicate> predicates;
Coding coding;
for (TranslationQuery translationQuery : translationQueries) {
cachedTargets = myTranslationCache.getIfPresent(translationQuery);
if (cachedTargets == null) {
final List<TermConceptMapGroupElementTarget> targets = new ArrayList<>();
predicates = new ArrayList<>();
coding = translationQuery.getCoding();
if (coding.hasCode()) {
predicates.add(criteriaBuilder.equal(elementJoin.get("myCode"), coding.getCode()));
} else {
throw new InvalidRequestException("A code must be provided for translation to occur.");
}
if (coding.hasSystem()) {
predicates.add(criteriaBuilder.equal(groupJoin.get("mySource"), coding.getSystem()));
}
if (coding.hasVersion()) {
predicates.add(criteriaBuilder.equal(groupJoin.get("mySourceVersion"), coding.getVersion()));
}
if (translationQuery.hasTargetSystem()) {
predicates.add(criteriaBuilder.equal(groupJoin.get("myTarget"), translationQuery.getTargetSystem().getValueAsString()));
}
if (translationQuery.hasSource()) {
predicates.add(criteriaBuilder.equal(conceptMapJoin.get("mySource"), translationQuery.getSource().getValueAsString()));
}
if (translationQuery.hasTarget()) {
predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myTarget"), translationQuery.getTarget().getValueAsString()));
}
if (translationQuery.hasResourceId()) {
predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myResourcePid"), translationQuery.getResourceId()));
}
Predicate outerPredicate = criteriaBuilder.and(predicates.toArray(new Predicate[0]));
query.where(outerPredicate);
// Use scrollable results.
final TypedQuery<TermConceptMapGroupElementTarget> typedQuery = myEntityManager.createQuery(query.select(root));
org.hibernate.query.Query<TermConceptMapGroupElementTarget> hibernateQuery = (org.hibernate.query.Query<TermConceptMapGroupElementTarget>) typedQuery;
hibernateQuery.setFetchSize(myFetchSize);
ScrollableResults scrollableResults = hibernateQuery.scroll(ScrollMode.FORWARD_ONLY);
Iterator<TermConceptMapGroupElementTarget> scrollableResultsIterator = new ScrollableResultsIterator<>(scrollableResults);
while (scrollableResultsIterator.hasNext()) {
targets.add(scrollableResultsIterator.next());
}
ourLastResultsFromTranslationCache = false; // For testing.
myTranslationCache.get(translationQuery, k -> targets);
retVal.addAll(targets);
} else {
ourLastResultsFromTranslationCache = true; // For testing.
retVal.addAll(cachedTargets);
}
}
return retVal;
}
@Override
public List<TermConceptMapGroupElement> translateWithReverse(TranslationRequest theTranslationRequest) {
List<TermConceptMapGroupElement> retVal = new ArrayList<>();
CriteriaBuilder criteriaBuilder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<TermConceptMapGroupElement> query = criteriaBuilder.createQuery(TermConceptMapGroupElement.class);
Root<TermConceptMapGroupElement> root = query.from(TermConceptMapGroupElement.class);
Join<TermConceptMapGroupElement, TermConceptMapGroupElementTarget> targetJoin = root.join("myConceptMapGroupElementTargets");
Join<TermConceptMapGroupElement, TermConceptMapGroup> groupJoin = root.join("myConceptMapGroup");
Join<TermConceptMapGroup, TermConceptMap> conceptMapJoin = groupJoin.join("myConceptMap");
List<TranslationQuery> translationQueries = theTranslationRequest.getTranslationQueries();
List<TermConceptMapGroupElement> cachedElements;
ArrayList<Predicate> predicates;
Coding coding;
for (TranslationQuery translationQuery : translationQueries) {
cachedElements = myTranslationWithReverseCache.getIfPresent(translationQuery);
if (cachedElements == null) {
final List<TermConceptMapGroupElement> elements = new ArrayList<>();
predicates = new ArrayList<>();
coding = translationQuery.getCoding();
if (coding.hasCode()) {
predicates.add(criteriaBuilder.equal(targetJoin.get("myCode"), coding.getCode()));
} else {
throw new InvalidRequestException("A code must be provided for translation to occur.");
}
if (coding.hasSystem()) {
predicates.add(criteriaBuilder.equal(groupJoin.get("myTarget"), coding.getSystem()));
}
if (coding.hasVersion()) {
predicates.add(criteriaBuilder.equal(groupJoin.get("myTargetVersion"), coding.getVersion()));
}
if (translationQuery.hasTargetSystem()) {
predicates.add(criteriaBuilder.equal(groupJoin.get("mySource"), translationQuery.getTargetSystem().getValueAsString()));
}
if (translationQuery.hasSource()) {
predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myTarget"), translationQuery.getSource().getValueAsString()));
}
if (translationQuery.hasTarget()) {
predicates.add(criteriaBuilder.equal(conceptMapJoin.get("mySource"), translationQuery.getTarget().getValueAsString()));
}
if (translationQuery.hasResourceId()) {
predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myResourcePid"), translationQuery.getResourceId()));
}
Predicate outerPredicate = criteriaBuilder.and(predicates.toArray(new Predicate[0]));
query.where(outerPredicate);
// Use scrollable results.
final TypedQuery<TermConceptMapGroupElement> typedQuery = myEntityManager.createQuery(query.select(root));
org.hibernate.query.Query<TermConceptMapGroupElement> hibernateQuery = (org.hibernate.query.Query<TermConceptMapGroupElement>) typedQuery;
hibernateQuery.setFetchSize(myFetchSize);
ScrollableResults scrollableResults = hibernateQuery.scroll(ScrollMode.FORWARD_ONLY);
Iterator<TermConceptMapGroupElement> scrollableResultsIterator = new ScrollableResultsIterator<>(scrollableResults);
while (scrollableResultsIterator.hasNext()) {
elements.add(scrollableResultsIterator.next());
}
ourLastResultsFromTranslationWithReverseCache = false; // For testing.
myTranslationWithReverseCache.get(translationQuery, k -> elements);
retVal.addAll(elements);
} else {
ourLastResultsFromTranslationWithReverseCache = true; // For testing.
retVal.addAll(cachedElements);
}
}
return retVal;
}
private int validateConceptForStorage(TermConcept theConcept, TermCodeSystemVersion theCodeSystem, ArrayList<String> theConceptsStack, private int validateConceptForStorage(TermConcept theConcept, TermCodeSystemVersion theCodeSystem, ArrayList<String> theConceptsStack,
IdentityHashMap<TermConcept, Object> theAllConcepts) { IdentityHashMap<TermConcept, Object> theAllConcepts) {
ValidateUtil.isTrueOrThrowInvalidRequest(theConcept.getCodeSystemVersion() != null, "CodesystemValue is null"); ValidateUtil.isTrueOrThrowInvalidRequest(theConcept.getCodeSystemVersion() != null, "CodesystemValue is null");
@ -921,6 +1233,54 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
} }
} }
/**
* This method is present only for unit tests, do not call from client code
*/
@VisibleForTesting
static void clearOurLastResultsFromTranslationCache() {
ourLastResultsFromTranslationCache = false;
}
/**
* This method is present only for unit tests, do not call from client code
*/
@VisibleForTesting
static void clearOurLastResultsFromTranslationWithReverseCache() {
ourLastResultsFromTranslationWithReverseCache = false;
}
/**
* This method is present only for unit tests, do not call from client code
*/
@VisibleForTesting
void clearTranslationCache() {
myTranslationCache.invalidateAll();
}
/**
* This method is present only for unit tests, do not call from client code
*/
@VisibleForTesting()
void clearTranslationWithReverseCache() {
myTranslationWithReverseCache.invalidateAll();
}
/**
* This method is present only for unit tests, do not call from client code
*/
@VisibleForTesting
static boolean isOurLastResultsFromTranslationCache() {
return ourLastResultsFromTranslationCache;
}
/**
* This method is present only for unit tests, do not call from client code
*/
@VisibleForTesting
static boolean isOurLastResultsFromTranslationWithReverseCache() {
return ourLastResultsFromTranslationWithReverseCache;
}
/** /**
* This method is present only for unit tests, do not call from client code * This method is present only for unit tests, do not call from client code
*/ */
@ -928,6 +1288,4 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
public static void setForceSaveDeferredAlwaysForUnitTest(boolean theForceSaveDeferredAlwaysForUnitTest) { public static void setForceSaveDeferredAlwaysForUnitTest(boolean theForceSaveDeferredAlwaysForUnitTest) {
ourForceSaveDeferredAlwaysForUnitTest = theForceSaveDeferredAlwaysForUnitTest; ourForceSaveDeferredAlwaysForUnitTest = theForceSaveDeferredAlwaysForUnitTest;
} }
} }

View File

@ -40,9 +40,9 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

View File

@ -1,10 +1,9 @@
package ca.uhn.fhir.jpa.term; package ca.uhn.fhir.jpa.term;
import ca.uhn.fhir.jpa.entity.TermCodeSystem; import ca.uhn.fhir.jpa.entity.*;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.ValueSet; import org.hl7.fhir.r4.model.ValueSet;
import java.util.List; import java.util.List;
@ -69,6 +68,11 @@ public interface IHapiTerminologySvc {
*/ */
IIdType storeNewCodeSystemVersion(org.hl7.fhir.r4.model.CodeSystem theCodeSystemResource, TermCodeSystemVersion theCodeSystemVersion, RequestDetails theRequestDetails, List<org.hl7.fhir.r4.model.ValueSet> theValueSets, List<org.hl7.fhir.r4.model.ConceptMap> theConceptMaps); IIdType storeNewCodeSystemVersion(org.hl7.fhir.r4.model.CodeSystem theCodeSystemResource, TermCodeSystemVersion theCodeSystemVersion, RequestDetails theRequestDetails, List<org.hl7.fhir.r4.model.ValueSet> theValueSets, List<org.hl7.fhir.r4.model.ConceptMap> theConceptMaps);
void storeTermConceptMapAndChildren(ResourceTable theResourceTable, ConceptMap theConceptMap);
boolean supportsSystem(String theCodeSystem); boolean supportsSystem(String theCodeSystem);
List<TermConceptMapGroupElementTarget> translate(TranslationRequest theTranslationRequest);
List<TermConceptMapGroupElement> translateWithReverse(TranslationRequest theTranslationRequest);
} }

View File

@ -0,0 +1,74 @@
package ca.uhn.fhir.jpa.term;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2018 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.hl7.fhir.r4.model.CodeType;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent;
import org.hl7.fhir.r4.model.UriType;
public class TranslationMatch {
private Coding myConcept;
private CodeType myEquivalence;
private UriType mySource;
public TranslationMatch() {
super();
}
public Coding getConcept() {
return myConcept;
}
public void setConcept(Coding theConcept) {
myConcept = theConcept;
}
public CodeType getEquivalence() {
return myEquivalence;
}
public void setEquivalence(CodeType theEquivalence) {
myEquivalence = theEquivalence;
}
public UriType getSource() {
return mySource;
}
public void setSource(UriType theSource) {
mySource = theSource;
}
public void toParameterParts(ParametersParameterComponent theParam) {
if (myEquivalence != null) {
theParam.addPart().setName("equivalence").setValue(myEquivalence);
}
if (myConcept != null) {
theParam.addPart().setName("concept").setValue(myConcept);
}
if (mySource != null) {
theParam.addPart().setName("source").setValue(mySource);
}
}
}

View File

@ -0,0 +1,128 @@
package ca.uhn.fhir.jpa.term;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2018 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.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.UriType;
public class TranslationQuery {
private Coding myCoding;
private Long myResourceId;
private UriType mySource;
private UriType myTarget;
private UriType myTargetSystem;
public TranslationQuery() {
super();
myCoding = new Coding();
}
public Coding getCoding() {
return myCoding;
}
public void setCoding(Coding theCoding) {
myCoding = theCoding;
}
public boolean hasResourceId() {
return myResourceId != null;
}
public Long getResourceId() {
return myResourceId;
}
public void setResourceId(Long theResourceId) {
myResourceId = theResourceId;
}
public boolean hasSource() {
return mySource != null && mySource.hasValue();
}
public UriType getSource() {
return mySource;
}
public void setSource(UriType theSource) {
mySource = theSource;
}
public boolean hasTarget() {
return myTarget != null && myTarget.hasValue();
}
public UriType getTarget() {
return myTarget;
}
public void setTarget(UriType theTarget) {
myTarget = theTarget;
}
public boolean hasTargetSystem() {
return myTargetSystem != null && myTargetSystem.hasValue();
}
public UriType getTargetSystem() {
return myTargetSystem;
}
public void setTargetSystem(UriType theTargetSystem) {
myTargetSystem = theTargetSystem;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TranslationQuery)) return false;
TranslationQuery that = (TranslationQuery) o;
return new EqualsBuilder()
.append(getCoding().getCode(), that.getCoding().getCode())
.append(getCoding().getSystem(), that.getCoding().getSystem())
.append(getCoding().getVersion(), that.getCoding().getVersion())
.append(getResourceId(), that.getResourceId())
.append(getSource(), that.getSource())
.append(getTarget(), that.getTarget())
.append(getTargetSystem(), that.getTargetSystem())
.isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder(17, 37)
.append(getCoding().getCode())
.append(getCoding().getSystem())
.append(getCoding().getVersion())
.append(getResourceId())
.append(getSource())
.append(getTarget())
.append(getTargetSystem())
.toHashCode();
}
}

View File

@ -0,0 +1,155 @@
package ca.uhn.fhir.jpa.term;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2018 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.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.UriType;
import java.util.ArrayList;
import java.util.List;
public class TranslationRequest {
private CodeableConcept myCodeableConcept;
private Long myResourceId;
private BooleanType myReverse;
private UriType mySource;
private UriType myTarget;
private UriType myTargetSystem;
public TranslationRequest() {
super();
myCodeableConcept = new CodeableConcept();
}
public CodeableConcept getCodeableConcept() {
return myCodeableConcept;
}
public void setCodeableConcept(CodeableConcept theCodeableConcept) {
myCodeableConcept = theCodeableConcept;
}
public boolean hasResourceId() {
return myResourceId != null;
}
public Long getResourceId() {
return myResourceId;
}
public void setResourceId(Long theResourceId) {
myResourceId = theResourceId;
}
public boolean hasReverse() {
return myReverse != null;
}
public BooleanType getReverse() {
return myReverse;
}
public boolean getReverseAsBoolean() {
if (hasReverse()) {
return myReverse.booleanValue();
}
return false;
}
public void setReverse(BooleanType theReverse) {
myReverse = theReverse;
}
public void setReverse(boolean theReverse) {
myReverse = new BooleanType(theReverse);
}
public boolean hasSource() {
return mySource != null && mySource.hasValue();
}
public UriType getSource() {
return mySource;
}
public void setSource(UriType theSource) {
mySource = theSource;
}
public boolean hasTarget() {
return myTarget != null && myTarget.hasValue();
}
public UriType getTarget() {
return myTarget;
}
public void setTarget(UriType theTarget) {
myTarget = theTarget;
}
public boolean hasTargetSystem() {
return myTargetSystem != null && myTargetSystem.hasValue();
}
public UriType getTargetSystem() {
return myTargetSystem;
}
public void setTargetSystem(UriType theTargetSystem) {
myTargetSystem = theTargetSystem;
}
public List<TranslationQuery> getTranslationQueries() {
List<TranslationQuery> retVal = new ArrayList<>();
TranslationQuery translationQuery;
for (Coding coding : getCodeableConcept().getCoding()) {
translationQuery = new TranslationQuery();
translationQuery.setCoding(coding);
if (this.hasResourceId()) {
translationQuery.setResourceId(this.getResourceId());
}
if (this.hasSource()) {
translationQuery.setSource(this.getSource());
}
if (this.hasTarget()) {
translationQuery.setTarget(this.getTarget());
}
if (this.hasTargetSystem()) {
translationQuery.setTargetSystem(this.getTargetSystem());
}
retVal.add(translationQuery);
}
return retVal;
}
}

View File

@ -0,0 +1,88 @@
package ca.uhn.fhir.jpa.term;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2018 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.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent;
import org.hl7.fhir.r4.model.StringType;
import java.util.ArrayList;
import java.util.List;
public class TranslationResult {
private List<TranslationMatch> myMatches;
private StringType myMessage;
private BooleanType myResult;
public TranslationResult() {
super();
myMatches = new ArrayList<>();
}
public List<TranslationMatch> getMatches() {
return myMatches;
}
public void setMatches(List<TranslationMatch> theMatches) {
myMatches = theMatches;
}
public boolean addMatch(TranslationMatch theMatch) {
return myMatches.add(theMatch);
}
public StringType getMessage() {
return myMessage;
}
public void setMessage(StringType theMessage) {
myMessage = theMessage;
}
public BooleanType getResult() {
return myResult;
}
public void setResult(BooleanType theMatched) {
myResult = theMatched;
}
public Parameters toParameters() {
Parameters retVal = new Parameters();
if (myResult != null) {
retVal.addParameter().setName("result").setValue(myResult);
}
if (myMessage != null) {
retVal.addParameter().setName("message").setValue(myMessage);
}
for (TranslationMatch translationMatch : myMatches) {
ParametersParameterComponent matchParam = retVal.addParameter().setName("match");
translationMatch.toParameterParts(matchParam);
}
return retVal;
}
}

View File

@ -160,4 +160,8 @@ public class JpaConstants {
*/ */
public static final String OPERATION_META_ADD = "$meta-add"; public static final String OPERATION_META_ADD = "$meta-add";
/**
* Operation name for the $translate operation
*/
public static final String OPERATION_TRANSLATE = "$translate";
} }

View File

@ -0,0 +1,63 @@
package ca.uhn.fhir.jpa.util;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2018 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.hibernate.ScrollableResults;
import java.util.Iterator;
public class ScrollableResultsIterator<T extends Object> extends BaseIterator<T> implements Iterator<T> {
private boolean hasNext;
private T myNext;
private ScrollableResults myScroll;
public ScrollableResultsIterator(ScrollableResults theScroll) {
myScroll = theScroll;
}
@SuppressWarnings("unchecked")
private void ensureHaveNext() {
if (myNext == null) {
if (myScroll.next()) {
hasNext = true;
myNext = (T) myScroll.get(0);
} else {
hasNext = false;
}
}
}
@Override
public boolean hasNext() {
ensureHaveNext();
return hasNext;
}
@Override
public T next() {
ensureHaveNext();
Validate.isTrue(hasNext);
T next = myNext;
myNext = null;
return next;
}
}

View File

@ -49,6 +49,15 @@ import static org.mockito.Mockito.when;
public abstract class BaseJpaTest { public abstract class BaseJpaTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseJpaTest.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseJpaTest.class);
protected static final String CM_URL = "http://example.com/my_concept_map";
protected static final String CS_URL = "http://example.com/my_code_system";
protected static final String CS_URL_2 = "http://example.com/my_code_system2";
protected static final String CS_URL_3 = "http://example.com/my_code_system3";
protected static final String CS_URL_4 = "http://example.com/my_code_system4";
protected static final String VS_URL = "http://example.com/my_value_set";
protected static final String VS_URL_2 = "http://example.com/my_value_set2";
protected ServletRequestDetails mySrd; protected ServletRequestDetails mySrd;
protected ArrayList<IServerInterceptor> myServerInterceptorList; protected ArrayList<IServerInterceptor> myServerInterceptorList;
protected IRequestOperationCallback myRequestOperationCallback = mock(IRequestOperationCallback.class); protected IRequestOperationCallback myRequestOperationCallback = mock(IRequestOperationCallback.class);

View File

@ -5,6 +5,7 @@ import ca.uhn.fhir.jpa.config.TestDstu3Config;
import ca.uhn.fhir.jpa.dao.*; import ca.uhn.fhir.jpa.dao.*;
import ca.uhn.fhir.jpa.dao.data.*; import ca.uhn.fhir.jpa.dao.data.*;
import ca.uhn.fhir.jpa.dao.dstu2.FhirResourceDaoDstu2SearchNoFtTest; import ca.uhn.fhir.jpa.dao.dstu2.FhirResourceDaoDstu2SearchNoFtTest;
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString; import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
import ca.uhn.fhir.jpa.entity.ResourceTable; import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3; import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
@ -14,20 +15,22 @@ import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc; import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc; import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
import ca.uhn.fhir.jpa.util.ResourceCountCache; import ca.uhn.fhir.jpa.util.ResourceCountCache;
import ca.uhn.fhir.jpa.util.SingleItemLoadingCache;
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu3; import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu3;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.parser.StrictErrorHandler; import ca.uhn.fhir.parser.StrictErrorHandler;
import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum; import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.util.UrlUtil; import ca.uhn.fhir.util.UrlUtil;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.hibernate.search.jpa.FullTextEntityManager; import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.Search; import org.hibernate.search.jpa.Search;
import org.hl7.fhir.convertors.VersionConvertor_30_40;
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport; import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
import org.hl7.fhir.dstu3.model.*; import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.After; import org.junit.After;
import org.junit.AfterClass; import org.junit.AfterClass;
@ -48,7 +51,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Map; import java.util.Map;
import static org.junit.Assert.*; import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ -91,7 +94,7 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
protected IFhirResourceDao<CompartmentDefinition> myCompartmentDefinitionDao; protected IFhirResourceDao<CompartmentDefinition> myCompartmentDefinitionDao;
@Autowired @Autowired
@Qualifier("myConceptMapDaoDstu3") @Qualifier("myConceptMapDaoDstu3")
protected IFhirResourceDao<ConceptMap> myConceptMapDao; protected IFhirResourceDaoConceptMap<ConceptMap> myConceptMapDao;
@Autowired @Autowired
@Qualifier("myConditionDaoDstu3") @Qualifier("myConditionDaoDstu3")
protected IFhirResourceDao<Condition> myConditionDao; protected IFhirResourceDao<Condition> myConditionDao;
@ -229,6 +232,10 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
protected IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> myValueSetDao; protected IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> myValueSetDao;
@Autowired @Autowired
private JpaValidationSupportChainDstu3 myJpaValidationSupportChainDstu3; private JpaValidationSupportChainDstu3 myJpaValidationSupportChainDstu3;
@Autowired
protected ITermConceptMapDao myTermConceptMapDao;
@Autowired
protected ITermConceptMapGroupElementTargetDao myTermConceptMapGroupElementTargetDao;
@After() @After()
public void afterCleanupDao() { public void afterCleanupDao() {
@ -315,4 +322,34 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
return uuid; return uuid;
} }
/**
* Creates a single {@link org.hl7.fhir.dstu3.model.ConceptMap} entity that includes:
* <br>
* <ul>
* <li>
* One group with two elements, each identifying one target apiece.
* </li>
* <li>
* One group with one element, identifying two targets.
* </li>
* <li>
* One group with one element, identifying a target that also appears
* in the first element of the first group.
* </li>
* </ul>
* </br>
* The first two groups identify the same source code system and different target code systems.
* </br>
* The first two groups also include an element with the same source code.
* </br>
*
* @return A {@link org.hl7.fhir.dstu3.model.ConceptMap} entity for testing.
*/
public static ConceptMap createConceptMap() {
try {
return VersionConvertor_30_40.convertConceptMap(BaseJpaR4Test.createConceptMap());
} catch (FHIRException fe) {
throw new InternalErrorException(fe);
}
}
} }

View File

@ -0,0 +1,84 @@
package ca.uhn.fhir.jpa.dao.dstu3;
import ca.uhn.fhir.jpa.term.TranslationMatch;
import ca.uhn.fhir.jpa.term.TranslationRequest;
import ca.uhn.fhir.jpa.term.TranslationResult;
import ca.uhn.fhir.util.TestUtil;
import org.hl7.fhir.dstu3.model.ConceptMap;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.Enumerations;
import org.hl7.fhir.r4.model.UriType;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import static org.junit.Assert.*;
public class FhirResourceDaoDstu3ConceptMapTest extends BaseJpaDstu3Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3ConceptMapTest.class);
private IIdType myConceptMapId;
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
}
@Before
@Transactional
public void before02() {
myConceptMapId = myConceptMapDao.create(createConceptMap(), mySrd).getId().toUnqualifiedVersionless();
}
@Test
public void testTranslateByCodeSystemsAndSourceCodeOneToMany() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
// <editor-fold desc="Map one source code to multiple target codes">
TranslationRequest translationRequest = new TranslationRequest();
translationRequest.getCodeableConcept().addCoding()
.setSystem(CS_URL)
.setCode("12345");
translationRequest.setTargetSystem(new UriType(CS_URL_3));
TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null);
assertTrue(translationResult.getResult().booleanValue());
assertEquals("Matches found!", translationResult.getMessage().getValueAsString());
assertEquals(2, translationResult.getMatches().size());
TranslationMatch translationMatch = translationResult.getMatches().get(0);
assertEquals(Enumerations.ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode());
Coding concept = translationMatch.getConcept();
assertEquals("56789", concept.getCode());
assertEquals("Target Code 56789", concept.getDisplay());
assertEquals(CS_URL_3, concept.getSystem());
assertEquals("Version 4", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
translationMatch = translationResult.getMatches().get(1);
assertEquals(Enumerations.ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence().getCode());
concept = translationMatch.getConcept();
assertEquals("67890", concept.getCode());
assertEquals("Target Code 67890", concept.getDisplay());
assertEquals(CS_URL_3, concept.getSystem());
assertEquals("Version 4", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
// </editor-fold>
}
});
}
}

View File

@ -29,6 +29,10 @@ import org.hibernate.search.jpa.Search;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport; import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
import org.hl7.fhir.r4.model.*; import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.ConceptMap.ConceptMapGroupComponent;
import org.hl7.fhir.r4.model.ConceptMap.SourceElementComponent;
import org.hl7.fhir.r4.model.ConceptMap.TargetElementComponent;
import org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence;
import org.junit.After; import org.junit.After;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Before; import org.junit.Before;
@ -48,13 +52,12 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Map; import java.util.Map;
import static org.junit.Assert.*; import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestR4Config.class}) @ContextConfiguration(classes = {TestR4Config.class})
public abstract class BaseJpaR4Test extends BaseJpaTest { public abstract class BaseJpaR4Test extends BaseJpaTest {
private static JpaValidationSupportChainR4 ourJpaValidationSupportChainR4; private static JpaValidationSupportChainR4 ourJpaValidationSupportChainR4;
private static IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> ourValueSetDao; private static IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> ourValueSetDao;
@ -102,7 +105,7 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
protected IFhirResourceDao<CompartmentDefinition> myCompartmentDefinitionDao; protected IFhirResourceDao<CompartmentDefinition> myCompartmentDefinitionDao;
@Autowired @Autowired
@Qualifier("myConceptMapDaoR4") @Qualifier("myConceptMapDaoR4")
protected IFhirResourceDao<ConceptMap> myConceptMapDao; protected IFhirResourceDaoConceptMap<ConceptMap> myConceptMapDao;
@Autowired @Autowired
@Qualifier("myConditionDaoR4") @Qualifier("myConditionDaoR4")
protected IFhirResourceDao<Condition> myConditionDao; protected IFhirResourceDao<Condition> myConditionDao;
@ -240,6 +243,10 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
protected IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> myValueSetDao; protected IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> myValueSetDao;
@Autowired @Autowired
private JpaValidationSupportChainR4 myJpaValidationSupportChainR4; private JpaValidationSupportChainR4 myJpaValidationSupportChainR4;
@Autowired
protected ITermConceptMapDao myTermConceptMapDao;
@Autowired
protected ITermConceptMapGroupElementTargetDao myTermConceptMapGroupElementTargetDao;
@After() @After()
public void afterCleanupDao() { public void afterCleanupDao() {
@ -327,4 +334,141 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
return uuid; return uuid;
} }
/**
* Creates a single {@link org.hl7.fhir.r4.model.ConceptMap} entity that includes:
* <br>
* <ul>
* <li>
* One group with two elements, each identifying one target apiece.
* </li>
* <li>
* One group with one element, identifying two targets.
* </li>
* <li>
* One group with one element, identifying a target that also appears
* in the first element of the first group.
* </li>
* </ul>
* </br>
* The first two groups identify the same source code system and different target code systems.
* </br>
* The first two groups also include an element with the same source code.
*
* @return A {@link org.hl7.fhir.r4.model.ConceptMap} entity for testing.
*/
public static ConceptMap createConceptMap() {
// <editor-fold desc="ConceptMap">
ConceptMap conceptMap = new ConceptMap();
conceptMap.setUrl(CM_URL);
conceptMap.setSource(new UriType(VS_URL));
conceptMap.setTarget(new UriType(VS_URL_2));
// <editor-fold desc="ConceptMap.group(0)">
ConceptMapGroupComponent group = conceptMap.addGroup();
group.setSource(CS_URL);
group.setSourceVersion("Version 1");
group.setTarget(CS_URL_2);
group.setTargetVersion("Version 2");
// <editor-fold desc="ConceptMap.group(0).element(0))">
SourceElementComponent element = group.addElement();
element.setCode("12345");
element.setDisplay("Source Code 12345");
// <editor-fold desc="ConceptMap.group(0).element(0).target(0)">
TargetElementComponent target = element.addTarget();
target.setCode("34567");
target.setDisplay("Target Code 34567");
target.setEquivalence(ConceptMapEquivalence.EQUAL);
// End ConceptMap.group(0).element(0).target(0)
// </editor-fold>
// End ConceptMap.group(0).element(0)
// </editor-fold>
// <editor-fold desc="ConceptMap.group(0).element(1))">
element = group.addElement();
element.setCode("23456");
element.setDisplay("Source Code 23456");
// <editor-fold desc="ConceptMap.group(0).element(1).target(0)">
target = element.addTarget();
target.setCode("45678");
target.setDisplay("Target Code 45678");
target.setEquivalence(ConceptMapEquivalence.WIDER);
// End ConceptMap.group(0).element(1).target(0)
// </editor-fold>
// End ConceptMap.group(0).element(1)
// </editor-fold>
// End ConceptMap.group(0)
// </editor-fold>
// <editor-fold desc="ConceptMap.group(1)">
group = conceptMap.addGroup();
group.setSource(CS_URL);
group.setSourceVersion("Version 3");
group.setTarget(CS_URL_3);
group.setTargetVersion("Version 4");
// <editor-fold desc="ConceptMap.group(1).element(0))">
element = group.addElement();
element.setCode("12345");
element.setDisplay("Source Code 12345");
// <editor-fold desc="ConceptMap.group(1).element(0).target(0)">
target = element.addTarget();
target.setCode("56789");
target.setDisplay("Target Code 56789");
target.setEquivalence(ConceptMapEquivalence.EQUAL);
// End ConceptMap.group(1).element(0).target(0)
// </editor-fold>
// <editor-fold desc="ConceptMap.group(1).element(0).target(1)">
target = element.addTarget();
target.setCode("67890");
target.setDisplay("Target Code 67890");
target.setEquivalence(ConceptMapEquivalence.WIDER);
// End ConceptMap.group(1).element(0).target(1)
// </editor-fold>
// End ConceptMap.group(1).element(0)
// </editor-fold>
// End ConceptMap.group(1)
// </editor-fold>
// <editor-fold desc="ConceptMap.group(2)">
group = conceptMap.addGroup();
group.setSource(CS_URL_4);
group.setSourceVersion("Version 5");
group.setTarget(CS_URL_2);
group.setTargetVersion("Version 2");
// <editor-fold desc="ConceptMap.group(2).element(0))">
element = group.addElement();
element.setCode("78901");
element.setDisplay("Source Code 78901");
// <editor-fold desc="ConceptMap.group(2).element(0).target(0)">
target = element.addTarget();
target.setCode("34567");
target.setDisplay("Target Code 34567");
target.setEquivalence(ConceptMapEquivalence.NARROWER);
// End ConceptMap.group(2).element(0).target(0)
// </editor-fold>
// End ConceptMap.group(2).element(0)
// </editor-fold>
// End ConceptMap.group(2)
// </editor-fold>
// End ConceptMap
// </editor-fold>
return conceptMap;
}
} }

View File

@ -0,0 +1,980 @@
package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.jpa.term.TranslationMatch;
import ca.uhn.fhir.jpa.term.TranslationRequest;
import ca.uhn.fhir.jpa.term.TranslationResult;
import ca.uhn.fhir.util.TestUtil;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence;
import org.hl7.fhir.r4.model.UriType;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import static org.junit.Assert.*;
public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test {
private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoR4ConceptMapTest.class);
private IIdType myConceptMapId;
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
}
@Before
@Transactional
public void before02() {
myConceptMapId = myConceptMapDao.create(createConceptMap(), mySrd).getId().toUnqualifiedVersionless();
}
@Test
public void testTranslateByCodeSystemsAndSourceCodeOneToMany() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
// <editor-fold desc="Map one source code to multiple target codes">
TranslationRequest translationRequest = new TranslationRequest();
translationRequest.getCodeableConcept().addCoding()
.setSystem(CS_URL)
.setCode("12345");
translationRequest.setTargetSystem(new UriType(CS_URL_3));
TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null);
assertTrue(translationResult.getResult().booleanValue());
assertEquals("Matches found!", translationResult.getMessage().getValueAsString());
assertEquals(2, translationResult.getMatches().size());
TranslationMatch translationMatch = translationResult.getMatches().get(0);
assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode());
Coding concept = translationMatch.getConcept();
assertEquals("56789", concept.getCode());
assertEquals("Target Code 56789", concept.getDisplay());
assertEquals(CS_URL_3, concept.getSystem());
assertEquals("Version 4", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
translationMatch = translationResult.getMatches().get(1);
assertEquals(ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence().getCode());
concept = translationMatch.getConcept();
assertEquals("67890", concept.getCode());
assertEquals("Target Code 67890", concept.getDisplay());
assertEquals(CS_URL_3, concept.getSystem());
assertEquals("Version 4", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
// </editor-fold>
}
});
}
@Test
public void testTranslateByCodeSystemsAndSourceCodeOneToOne() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
// <editor-fold desc="Map one source code to one target code">
TranslationRequest translationRequest = new TranslationRequest();
translationRequest.getCodeableConcept().addCoding()
.setSystem(CS_URL)
.setCode("12345");
translationRequest.setTargetSystem(new UriType(CS_URL_2));
TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null);
assertTrue(translationResult.getResult().booleanValue());
assertEquals("Matches found!", translationResult.getMessage().getValueAsString());
assertEquals(1, translationResult.getMatches().size());
TranslationMatch translationMatch = translationResult.getMatches().get(0);
assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode());
Coding concept = translationMatch.getConcept();
assertEquals("34567", concept.getCode());
assertEquals("Target Code 34567", concept.getDisplay());
assertEquals(CS_URL_2, concept.getSystem());
assertEquals("Version 2", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
// </editor-fold>
}
});
}
@Test
public void testTranslateByCodeSystemsAndSourceCodeUnmapped() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
// <editor-fold desc="Attempt to map unknown source code">
TranslationRequest translationRequest = new TranslationRequest();
translationRequest.getCodeableConcept().addCoding()
.setSystem(CS_URL)
.setCode("BOGUS");
translationRequest.setTargetSystem(new UriType(CS_URL_3));
TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null);
assertFalse(translationResult.getResult().booleanValue());
assertEquals("No matches found!", translationResult.getMessage().getValueAsString());
assertEquals(0, translationResult.getMatches().size());
// </editor-fold>
}
});
}
@Test
public void testTranslateUsingPredicatesWithCodeOnly() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
/*
* Provided:
* source code
*/
TranslationRequest translationRequest = new TranslationRequest();
translationRequest.getCodeableConcept().addCoding()
.setCode("12345");
TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null);
assertTrue(translationResult.getResult().booleanValue());
assertEquals("Matches found!", translationResult.getMessage().getValueAsString());
assertEquals(3, translationResult.getMatches().size());
TranslationMatch translationMatch = translationResult.getMatches().get(0);
assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode());
Coding concept = translationMatch.getConcept();
assertEquals("34567", concept.getCode());
assertEquals("Target Code 34567", concept.getDisplay());
assertEquals(CS_URL_2, concept.getSystem());
assertEquals("Version 2", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
translationMatch = translationResult.getMatches().get(1);
assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode());
concept = translationMatch.getConcept();
assertEquals("56789", concept.getCode());
assertEquals("Target Code 56789", concept.getDisplay());
assertEquals(CS_URL_3, concept.getSystem());
assertEquals("Version 4", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
translationMatch = translationResult.getMatches().get(2);
assertEquals(ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence().getCode());
concept = translationMatch.getConcept();
assertEquals("67890", concept.getCode());
assertEquals("Target Code 67890", concept.getDisplay());
assertEquals(CS_URL_3, concept.getSystem());
assertEquals("Version 4", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
}
});
}
@Test
public void testTranslateUsingPredicatesWithSourceSystem() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
/*
* Provided:
* source code
* source code system
*/
TranslationRequest translationRequest = new TranslationRequest();
translationRequest.getCodeableConcept().addCoding()
.setSystem(CS_URL)
.setCode("12345");
TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null);
assertTrue(translationResult.getResult().booleanValue());
assertEquals("Matches found!", translationResult.getMessage().getValueAsString());
assertEquals(3, translationResult.getMatches().size());
TranslationMatch translationMatch = translationResult.getMatches().get(0);
assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode());
Coding concept = translationMatch.getConcept();
assertEquals("34567", concept.getCode());
assertEquals("Target Code 34567", concept.getDisplay());
assertEquals(CS_URL_2, concept.getSystem());
assertEquals("Version 2", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
translationMatch = translationResult.getMatches().get(1);
assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode());
concept = translationMatch.getConcept();
assertEquals("56789", concept.getCode());
assertEquals("Target Code 56789", concept.getDisplay());
assertEquals(CS_URL_3, concept.getSystem());
assertEquals("Version 4", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
translationMatch = translationResult.getMatches().get(2);
assertEquals(ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence().getCode());
concept = translationMatch.getConcept();
assertEquals("67890", concept.getCode());
assertEquals("Target Code 67890", concept.getDisplay());
assertEquals(CS_URL_3, concept.getSystem());
assertEquals("Version 4", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
}
});
}
@Test
public void testTranslateUsingPredicatesWithSourceSystemAndVersion1() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
/*
* Provided:
* source code
* source code system
* source code system version #1
*/
TranslationRequest translationRequest = new TranslationRequest();
translationRequest.getCodeableConcept().addCoding()
.setSystem(CS_URL)
.setCode("12345")
.setVersion("Version 1");
TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null);
assertTrue(translationResult.getResult().booleanValue());
assertEquals("Matches found!", translationResult.getMessage().getValueAsString());
assertEquals(1, translationResult.getMatches().size());
TranslationMatch translationMatch = translationResult.getMatches().get(0);
assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode());
Coding concept = translationMatch.getConcept();
assertEquals("34567", concept.getCode());
assertEquals("Target Code 34567", concept.getDisplay());
assertEquals(CS_URL_2, concept.getSystem());
assertEquals("Version 2", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
}
});
}
@Test
public void testTranslateUsingPredicatesWithSourceSystemAndVersion3() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
/*
* Provided:
* source code
* source code system
* source code system version #3
*/
TranslationRequest translationRequest = new TranslationRequest();
translationRequest.getCodeableConcept().addCoding()
.setSystem(CS_URL)
.setCode("12345")
.setVersion("Version 3");
TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null);
assertTrue(translationResult.getResult().booleanValue());
assertEquals("Matches found!", translationResult.getMessage().getValueAsString());
assertEquals(2, translationResult.getMatches().size());
TranslationMatch translationMatch = translationResult.getMatches().get(0);
assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode());
Coding concept = translationMatch.getConcept();
assertEquals("56789", concept.getCode());
assertEquals("Target Code 56789", concept.getDisplay());
assertEquals(CS_URL_3, concept.getSystem());
assertEquals("Version 4", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
translationMatch = translationResult.getMatches().get(1);
assertEquals(ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence().getCode());
concept = translationMatch.getConcept();
assertEquals("67890", concept.getCode());
assertEquals("Target Code 67890", concept.getDisplay());
assertEquals(CS_URL_3, concept.getSystem());
assertEquals("Version 4", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
}
});
}
@Test
public void testTranslateUsingPredicatesWithSourceAndTargetSystem2() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
/*
* Provided:
* source code
* source code system
* target code system #2
*/
TranslationRequest translationRequest = new TranslationRequest();
translationRequest.getCodeableConcept().addCoding()
.setSystem(CS_URL)
.setCode("12345");
translationRequest.setTargetSystem(new UriType(CS_URL_2));
TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null);
assertTrue(translationResult.getResult().booleanValue());
assertEquals("Matches found!", translationResult.getMessage().getValueAsString());
assertEquals(1, translationResult.getMatches().size());
TranslationMatch translationMatch = translationResult.getMatches().get(0);
assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode());
Coding concept = translationMatch.getConcept();
assertEquals("34567", concept.getCode());
assertEquals("Target Code 34567", concept.getDisplay());
assertEquals(CS_URL_2, concept.getSystem());
assertEquals("Version 2", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
}
});
}
@Test
public void testTranslateUsingPredicatesWithSourceAndTargetSystem3() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
/*
* Provided:
* source code
* source code system
* target code system #3
*/
TranslationRequest translationRequest = new TranslationRequest();
translationRequest.getCodeableConcept().addCoding()
.setSystem(CS_URL)
.setCode("12345");
translationRequest.setTargetSystem(new UriType(CS_URL_3));
TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null);
assertTrue(translationResult.getResult().booleanValue());
assertEquals("Matches found!", translationResult.getMessage().getValueAsString());
assertEquals(2, translationResult.getMatches().size());
TranslationMatch translationMatch = translationResult.getMatches().get(0);
assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode());
Coding concept = translationMatch.getConcept();
assertEquals("56789", concept.getCode());
assertEquals("Target Code 56789", concept.getDisplay());
assertEquals(CS_URL_3, concept.getSystem());
assertEquals("Version 4", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
translationMatch = translationResult.getMatches().get(1);
assertEquals(ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence().getCode());
concept = translationMatch.getConcept();
assertEquals("67890", concept.getCode());
assertEquals("Target Code 67890", concept.getDisplay());
assertEquals(CS_URL_3, concept.getSystem());
assertEquals("Version 4", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
}
});
}
@Test
public void testTranslateUsingPredicatesWithSourceValueSet() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
/*
* Provided:
* source code
* source value set
*/
TranslationRequest translationRequest = new TranslationRequest();
translationRequest.getCodeableConcept().addCoding()
.setCode("12345");
translationRequest.setSource(new UriType(VS_URL));
TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null);
assertTrue(translationResult.getResult().booleanValue());
assertEquals("Matches found!", translationResult.getMessage().getValueAsString());
assertEquals(3, translationResult.getMatches().size());
TranslationMatch translationMatch = translationResult.getMatches().get(0);
assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode());
Coding concept = translationMatch.getConcept();
assertEquals("34567", concept.getCode());
assertEquals("Target Code 34567", concept.getDisplay());
assertEquals(CS_URL_2, concept.getSystem());
assertEquals("Version 2", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
translationMatch = translationResult.getMatches().get(1);
assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode());
concept = translationMatch.getConcept();
assertEquals("56789", concept.getCode());
assertEquals("Target Code 56789", concept.getDisplay());
assertEquals(CS_URL_3, concept.getSystem());
assertEquals("Version 4", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
translationMatch = translationResult.getMatches().get(2);
assertEquals(ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence().getCode());
concept = translationMatch.getConcept();
assertEquals("67890", concept.getCode());
assertEquals("Target Code 67890", concept.getDisplay());
assertEquals(CS_URL_3, concept.getSystem());
assertEquals("Version 4", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
}
});
}
@Test
public void testTranslateUsingPredicatesWithTargetValueSet() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
/*
* Provided:
* source code
* target value set
*/
TranslationRequest translationRequest = new TranslationRequest();
translationRequest.getCodeableConcept().addCoding()
.setCode("12345");
translationRequest.setTarget(new UriType(VS_URL_2));
TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null);
assertTrue(translationResult.getResult().booleanValue());
assertEquals("Matches found!", translationResult.getMessage().getValueAsString());
assertEquals(3, translationResult.getMatches().size());
TranslationMatch translationMatch = translationResult.getMatches().get(0);
assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode());
Coding concept = translationMatch.getConcept();
assertEquals("34567", concept.getCode());
assertEquals("Target Code 34567", concept.getDisplay());
assertEquals(CS_URL_2, concept.getSystem());
assertEquals("Version 2", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
translationMatch = translationResult.getMatches().get(1);
assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode());
concept = translationMatch.getConcept();
assertEquals("56789", concept.getCode());
assertEquals("Target Code 56789", concept.getDisplay());
assertEquals(CS_URL_3, concept.getSystem());
assertEquals("Version 4", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
translationMatch = translationResult.getMatches().get(2);
assertEquals(ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence().getCode());
concept = translationMatch.getConcept();
assertEquals("67890", concept.getCode());
assertEquals("Target Code 67890", concept.getDisplay());
assertEquals(CS_URL_3, concept.getSystem());
assertEquals("Version 4", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
}
});
}
@Test
public void testTranslateWithReverse() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
/*
* Provided:
* source code
* source code system
* target code system
* reverse = true
*/
TranslationRequest translationRequest = new TranslationRequest();
translationRequest.getCodeableConcept().addCoding()
.setSystem(CS_URL_2)
.setCode("34567");
translationRequest.setTargetSystem(new UriType(CS_URL_4));
translationRequest.setReverse(true);
TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null);
assertTrue(translationResult.getResult().booleanValue());
assertEquals("Matches found!", translationResult.getMessage().getValueAsString());
assertEquals(1, translationResult.getMatches().size());
TranslationMatch translationMatch = translationResult.getMatches().get(0);
assertNull(translationMatch.getEquivalence());
Coding concept = translationMatch.getConcept();
assertEquals("78901", concept.getCode());
assertEquals("Source Code 78901", concept.getDisplay());
assertEquals(CS_URL_4, concept.getSystem());
assertEquals("Version 5", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
}
});
}
@Test
public void testTranslateWithReverseByCodeSystemsAndSourceCodeUnmapped() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
// <editor-fold desc="Attempt to map unknown source code">
TranslationRequest translationRequest = new TranslationRequest();
translationRequest.getCodeableConcept().addCoding()
.setSystem(CS_URL_3)
.setCode("BOGUS");
translationRequest.setTargetSystem(new UriType(CS_URL));
translationRequest.setReverse(true);
TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null);
assertFalse(translationResult.getResult().booleanValue());
assertEquals("No matches found!", translationResult.getMessage().getValueAsString());
assertEquals(0, translationResult.getMatches().size());
// </editor-fold>
}
});
}
@Test
public void testTranslateWithReverseUsingPredicatesWithCodeOnly() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
/*
* Provided:
* source code
* reverse = true
*/
TranslationRequest translationRequest = new TranslationRequest();
translationRequest.getCodeableConcept().addCoding()
.setCode("34567");
translationRequest.setReverse(true);
TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null);
assertTrue(translationResult.getResult().booleanValue());
assertEquals("Matches found!", translationResult.getMessage().getValueAsString());
assertEquals(2, translationResult.getMatches().size());
TranslationMatch translationMatch = translationResult.getMatches().get(0);
assertNull(translationMatch.getEquivalence());
Coding concept = translationMatch.getConcept();
assertEquals("12345", concept.getCode());
assertEquals("Source Code 12345", concept.getDisplay());
assertEquals(CS_URL, concept.getSystem());
assertEquals("Version 1", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
translationMatch = translationResult.getMatches().get(1);
assertNull(translationMatch.getEquivalence());
concept = translationMatch.getConcept();
assertEquals("78901", concept.getCode());
assertEquals("Source Code 78901", concept.getDisplay());
assertEquals(CS_URL_4, concept.getSystem());
assertEquals("Version 5", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
}
});
}
@Test
public void testTranslateWithReverseUsingPredicatesWithSourceSystem() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
/*
* Provided:
* source code
* source code system
* reverse = true
*/
TranslationRequest translationRequest = new TranslationRequest();
translationRequest.getCodeableConcept().addCoding()
.setSystem(CS_URL_2)
.setCode("34567");
translationRequest.setReverse(true);
TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null);
assertTrue(translationResult.getResult().booleanValue());
assertEquals("Matches found!", translationResult.getMessage().getValueAsString());
assertEquals(2, translationResult.getMatches().size());
TranslationMatch translationMatch = translationResult.getMatches().get(0);
assertNull(translationMatch.getEquivalence());
Coding concept = translationMatch.getConcept();
assertEquals("12345", concept.getCode());
assertEquals("Source Code 12345", concept.getDisplay());
assertEquals(CS_URL, concept.getSystem());
assertEquals("Version 1", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
translationMatch = translationResult.getMatches().get(1);
assertNull(translationMatch.getEquivalence());
concept = translationMatch.getConcept();
assertEquals("78901", concept.getCode());
assertEquals("Source Code 78901", concept.getDisplay());
assertEquals(CS_URL_4, concept.getSystem());
assertEquals("Version 5", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
}
});
}
@Test
public void testTranslateWithReverseUsingPredicatesWithSourceSystemAndVersion() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
/*
* Provided:
* source code
* source code system
* source code system version
* reverse = true
*/
TranslationRequest translationRequest = new TranslationRequest();
translationRequest.getCodeableConcept().addCoding()
.setSystem(CS_URL_2)
.setCode("34567")
.setVersion("Version 2");
translationRequest.setReverse(true);
TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null);
assertTrue(translationResult.getResult().booleanValue());
assertEquals("Matches found!", translationResult.getMessage().getValueAsString());
assertEquals(2, translationResult.getMatches().size());
TranslationMatch translationMatch = translationResult.getMatches().get(0);
assertNull(translationMatch.getEquivalence());
Coding concept = translationMatch.getConcept();
assertEquals("12345", concept.getCode());
assertEquals("Source Code 12345", concept.getDisplay());
assertEquals(CS_URL, concept.getSystem());
assertEquals("Version 1", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
translationMatch = translationResult.getMatches().get(1);
assertNull(translationMatch.getEquivalence());
concept = translationMatch.getConcept();
assertEquals("78901", concept.getCode());
assertEquals("Source Code 78901", concept.getDisplay());
assertEquals(CS_URL_4, concept.getSystem());
assertEquals("Version 5", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
}
});
}
@Test
public void testTranslateWithReverseUsingPredicatesWithSourceAndTargetSystem1() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
/*
* Provided:
* source code
* source code system
* target code system #1
* reverse = true
*/
TranslationRequest translationRequest = new TranslationRequest();
translationRequest.getCodeableConcept().addCoding()
.setSystem(CS_URL_2)
.setCode("34567");
translationRequest.setTargetSystem(new UriType(CS_URL));
translationRequest.setReverse(true);
TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null);
assertTrue(translationResult.getResult().booleanValue());
assertEquals("Matches found!", translationResult.getMessage().getValueAsString());
assertEquals(1, translationResult.getMatches().size());
TranslationMatch translationMatch = translationResult.getMatches().get(0);
assertNull(translationMatch.getEquivalence());
Coding concept = translationMatch.getConcept();
assertEquals("12345", concept.getCode());
assertEquals("Source Code 12345", concept.getDisplay());
assertEquals(CS_URL, concept.getSystem());
assertEquals("Version 1", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
}
});
}
@Test
public void testTranslateWithReverseUsingPredicatesWithSourceAndTargetSystem4() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
/*
* Provided:
* source code
* source code system
* target code system #4
* reverse = true
*/
TranslationRequest translationRequest = new TranslationRequest();
translationRequest.getCodeableConcept().addCoding()
.setSystem(CS_URL_2)
.setCode("34567");
translationRequest.setTargetSystem(new UriType(CS_URL_4));
translationRequest.setReverse(true);
TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null);
assertTrue(translationResult.getResult().booleanValue());
assertEquals("Matches found!", translationResult.getMessage().getValueAsString());
assertEquals(1, translationResult.getMatches().size());
TranslationMatch translationMatch = translationResult.getMatches().get(0);
assertNull(translationMatch.getEquivalence());
Coding concept = translationMatch.getConcept();
assertEquals("78901", concept.getCode());
assertEquals("Source Code 78901", concept.getDisplay());
assertEquals(CS_URL_4, concept.getSystem());
assertEquals("Version 5", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
}
});
}
@Test
public void testTranslateWithReverseUsingPredicatesWithSourceValueSet() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
/*
* Provided:
* source code
* source value set
* reverse = true
*/
TranslationRequest translationRequest = new TranslationRequest();
translationRequest.getCodeableConcept().addCoding()
.setCode("34567");
translationRequest.setSource(new UriType(VS_URL_2));
translationRequest.setReverse(true);
TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null);
assertTrue(translationResult.getResult().booleanValue());
assertEquals("Matches found!", translationResult.getMessage().getValueAsString());
assertEquals(2, translationResult.getMatches().size());
TranslationMatch translationMatch = translationResult.getMatches().get(0);
assertNull(translationMatch.getEquivalence());
Coding concept = translationMatch.getConcept();
assertEquals("12345", concept.getCode());
assertEquals("Source Code 12345", concept.getDisplay());
assertEquals(CS_URL, concept.getSystem());
assertEquals("Version 1", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
translationMatch = translationResult.getMatches().get(1);
assertNull(translationMatch.getEquivalence());
concept = translationMatch.getConcept();
assertEquals("78901", concept.getCode());
assertEquals("Source Code 78901", concept.getDisplay());
assertEquals(CS_URL_4, concept.getSystem());
assertEquals("Version 5", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
}
});
}
@Test
public void testTranslateWithReverseUsingPredicatesWithTargetValueSet() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
/*
* Provided:
* source code
* target value set
* reverse = true
*/
TranslationRequest translationRequest = new TranslationRequest();
translationRequest.getCodeableConcept().addCoding()
.setCode("34567");
translationRequest.setTarget(new UriType(VS_URL));
translationRequest.setReverse(true);
TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null);
assertTrue(translationResult.getResult().booleanValue());
assertEquals("Matches found!", translationResult.getMessage().getValueAsString());
assertEquals(2, translationResult.getMatches().size());
TranslationMatch translationMatch = translationResult.getMatches().get(0);
assertNull(translationMatch.getEquivalence());
Coding concept = translationMatch.getConcept();
assertEquals("12345", concept.getCode());
assertEquals("Source Code 12345", concept.getDisplay());
assertEquals(CS_URL, concept.getSystem());
assertEquals("Version 1", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
translationMatch = translationResult.getMatches().get(1);
assertNull(translationMatch.getEquivalence());
concept = translationMatch.getConcept();
assertEquals("78901", concept.getCode());
assertEquals("Source Code 78901", concept.getDisplay());
assertEquals(CS_URL_4, concept.getSystem());
assertEquals("Version 5", concept.getVersion());
assertFalse(concept.getUserSelected());
assertEquals(CM_URL, translationMatch.getSource().getValueAsString());
}
});
}
}

View File

@ -26,6 +26,8 @@ import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import org.hl7.fhir.dstu3.model.Bundle; import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent; import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.dstu3.model.Parameters;
import org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent;
import org.hl7.fhir.dstu3.model.Patient; import org.hl7.fhir.dstu3.model.Patient;
import org.junit.After; import org.junit.After;
import org.junit.AfterClass; import org.junit.AfterClass;
@ -201,4 +203,56 @@ public abstract class BaseResourceProviderDstu3Test extends BaseJpaDstu3Test {
TestUtil.clearAllStaticFieldsForUnitTest(); TestUtil.clearAllStaticFieldsForUnitTest();
} }
public static int getNumberOfParametersByName(Parameters theParameters, String theName) {
int retVal = 0;
for (ParametersParameterComponent param : theParameters.getParameter()) {
if (param.getName().equals(theName)) {
retVal++;
}
}
return retVal;
}
public static ParametersParameterComponent getParameterByName(Parameters theParameters, String theName) {
for (ParametersParameterComponent param : theParameters.getParameter()) {
if (param.getName().equals(theName)) {
return param;
}
}
return new ParametersParameterComponent();
}
public static List<ParametersParameterComponent> getParametersByName(Parameters theParameters, String theName) {
List<ParametersParameterComponent> params = new ArrayList<>();
for (ParametersParameterComponent param : theParameters.getParameter()) {
if (param.getName().equals(theName)) {
params.add(param);
}
}
return params;
}
public static ParametersParameterComponent getPartByName(ParametersParameterComponent theParameter, String theName) {
for (ParametersParameterComponent part : theParameter.getPart()) {
if (part.getName().equals(theName)) {
return part;
}
}
return new ParametersParameterComponent();
}
public static boolean hasParameterByName(Parameters theParameters, String theName) {
for (ParametersParameterComponent param : theParameters.getParameter()) {
if (param.getName().equals(theName)) {
return true;
}
}
return false;
}
} }

View File

@ -0,0 +1,89 @@
package ca.uhn.fhir.jpa.provider.dstu3;
import ca.uhn.fhir.util.TestUtil;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
import static org.junit.Assert.*;
public class ResourceProviderDstu3ConceptMapTest extends BaseResourceProviderDstu3Test {
private static final Logger ourLog = LoggerFactory.getLogger(ResourceProviderDstu3ConceptMapTest.class);
private IIdType myConceptMapId;
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
}
@Before
@Transactional
public void before02() {
myConceptMapId = myConceptMapDao.create(createConceptMap(), mySrd).getId().toUnqualifiedVersionless();
}
@Test
public void testTranslateByCodeSystemsAndSourceCodeOneToMany() {
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
Parameters inParams = new Parameters();
inParams.addParameter().setName("system").setValue(new UriType(CS_URL));
inParams.addParameter().setName("targetsystem").setValue(new UriType(CS_URL_3));
inParams.addParameter().setName("code").setValue(new CodeType("12345"));
ourLog.info("Request Parameters:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(inParams));
Parameters respParams = ourClient
.operation()
.onType(ConceptMap.class)
.named("translate")
.withParameters(inParams)
.execute();
ourLog.info("Response Parameters\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(respParams));
ParametersParameterComponent param = getParameterByName(respParams, "result");
assertTrue(((BooleanType) param.getValue()).booleanValue());
param = getParameterByName(respParams, "message");
assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString());
assertEquals(2, getNumberOfParametersByName(respParams, "match"));
param = getParametersByName(respParams, "match").get(0);
assertEquals(3, param.getPart().size());
ParametersParameterComponent part = getPartByName(param, "equivalence");
assertEquals("equal", ((CodeType) part.getValue()).getValueAsString());
part = getPartByName(param, "concept");
Coding coding = (Coding) part.getValue();
assertEquals("56789", coding.getCode());
assertEquals("Target Code 56789", coding.getDisplay());
assertFalse(coding.getUserSelected());
assertEquals(CS_URL_3, coding.getSystem());
assertEquals("Version 4", coding.getVersion());
part = getPartByName(param, "source");
assertEquals(CM_URL, ((UriType) part.getValue()).getValueAsString());
param = getParametersByName(respParams, "match").get(1);
assertEquals(3, param.getPart().size());
part = getPartByName(param, "equivalence");
assertEquals("wider", ((CodeType) part.getValue()).getValueAsString());
part = getPartByName(param, "concept");
coding = (Coding) part.getValue();
assertEquals("67890", coding.getCode());
assertEquals("Target Code 67890", coding.getDisplay());
assertFalse(coding.getUserSelected());
assertEquals(CS_URL_3, coding.getSystem());
assertEquals("Version 4", coding.getVersion());
part = getPartByName(param, "source");
assertEquals(CM_URL, ((UriType) part.getValue()).getValueAsString());
}
}

View File

@ -27,6 +27,8 @@ import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent;
import org.hl7.fhir.r4.model.Patient; import org.hl7.fhir.r4.model.Patient;
import org.junit.After; import org.junit.After;
import org.junit.AfterClass; import org.junit.AfterClass;
@ -215,4 +217,56 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test {
TestUtil.clearAllStaticFieldsForUnitTest(); TestUtil.clearAllStaticFieldsForUnitTest();
} }
public static int getNumberOfParametersByName(Parameters theParameters, String theName) {
int retVal = 0;
for (ParametersParameterComponent param : theParameters.getParameter()) {
if (param.getName().equals(theName)) {
retVal++;
}
}
return retVal;
}
public static ParametersParameterComponent getParameterByName(Parameters theParameters, String theName) {
for (ParametersParameterComponent param : theParameters.getParameter()) {
if (param.getName().equals(theName)) {
return param;
}
}
return new ParametersParameterComponent();
}
public static List<ParametersParameterComponent> getParametersByName(Parameters theParameters, String theName) {
List<ParametersParameterComponent> params = new ArrayList<>();
for (ParametersParameterComponent param : theParameters.getParameter()) {
if (param.getName().equals(theName)) {
params.add(param);
}
}
return params;
}
public static ParametersParameterComponent getPartByName(ParametersParameterComponent theParameter, String theName) {
for (ParametersParameterComponent part : theParameter.getPart()) {
if (part.getName().equals(theName)) {
return part;
}
}
return new ParametersParameterComponent();
}
public static boolean hasParameterByName(Parameters theParameters, String theName) {
for (ParametersParameterComponent param : theParameters.getParameter()) {
if (param.getName().equals(theName)) {
return true;
}
}
return false;
}
} }

View File

@ -430,5 +430,4 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
public static void afterClassClearContext() { public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest(); TestUtil.clearAllStaticFieldsForUnitTest();
} }
} }

View File

@ -18,7 +18,7 @@ public class PublicSecurityInterceptor extends AuthorizationInterceptor {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(PublicSecurityInterceptor.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(PublicSecurityInterceptor.class);
private HashSet<String> myTokens; private HashSet<String> myTokens;
public PublicSecurityInterceptor() { public PublicSecurityInterceptor() {
String passwordsString = System.getProperty("fhir.tdlpass"); String passwordsString = System.getProperty("fhir.tdlpass");
String[] passwords = passwordsString.split(","); String[] passwords = passwordsString.split(",");

View File

@ -5,11 +5,7 @@ import java.util.*;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
#if ( $version != 'dstu' && (${className} == 'Encounter' || ${className} == 'Patient' || ${className} == 'ValueSet' || ${className} == 'QuestionnaireAnswers' || ${className} == 'CodeSystem')) import ca.uhn.fhir.jpa.provider${package_suffix}.*;
import ca.uhn.fhir.jpa.provider${package_suffix}.BaseJpaResourceProvider${className}${versionCapitalized};
#else
import ca.uhn.fhir.jpa.provider${package_suffix}.JpaResourceProvider${versionCapitalized};
#end
import ca.uhn.fhir.jpa.dao.SearchParameterMap; import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.model.api.Include; import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.annotation.*; import ca.uhn.fhir.model.api.annotation.*;
@ -26,7 +22,7 @@ import ca.uhn.fhir.rest.api.SortSpec;
public class ${className}ResourceProvider extends public class ${className}ResourceProvider extends
## We have specialized base classes for RPs that handle certain resource types. These ## We have specialized base classes for RPs that handle certain resource types. These
## RPs implement type specific operations ## RPs implement type specific operations
#if ( $version != 'dstu' && (${className} == 'Encounter' || ${className} == 'Patient' || ${className} == 'ValueSet' || ${className} == 'QuestionnaireAnswers' || ${className} == 'CodeSystem')) #if ( $version != 'dstu' && (${className} == 'Encounter' || ${className} == 'Patient' || ${className} == 'ValueSet' || ${className} == 'QuestionnaireAnswers' || ${className} == 'CodeSystem' || ($version != 'dstu2' && ${className} == 'ConceptMap')))
BaseJpaResourceProvider${className}${versionCapitalized} BaseJpaResourceProvider${className}${versionCapitalized}
#else #else
JpaResourceProvider${versionCapitalized}<${className}> JpaResourceProvider${versionCapitalized}<${className}>

View File

@ -44,7 +44,11 @@
#foreach ( $res in $resources ) #foreach ( $res in $resources )
<bean id="my${res.name}Dao${versionCapitalized}" <bean id="my${res.name}Dao${versionCapitalized}"
## Some resource types have customized DAOs for resource specific functionality ## Some resource types have customized DAOs for resource specific functionality
#if ( ${versionCapitalized} != 'Dstu1' && ( ${res.name} == 'Bundle' || ${res.name} == 'Encounter' || ${res.name} == 'Everything' || ${res.name} == 'Patient' || ${res.name} == 'Subscription' || ${res.name} == 'ValueSet' || ${res.name} == 'QuestionnaireResponse' || ${res.name} == 'SearchParameter')) #if ( ${versionCapitalized} == 'Dstu3' && ${res.name} == 'ConceptMap')
class="ca.uhn.fhir.jpa.dao.FhirResourceDao${res.name}${versionCapitalized}">
#elseif ( ${versionCapitalized} == 'R4' && ${res.name} == 'ConceptMap')
class="ca.uhn.fhir.jpa.dao.FhirResourceDao${res.name}${versionCapitalized}">
#elseif ( ${versionCapitalized} != 'Dstu1' && ( ${res.name} == 'Bundle' || ${res.name} == 'Encounter' || ${res.name} == 'Everything' || ${res.name} == 'Patient' || ${res.name} == 'Subscription' || ${res.name} == 'ValueSet' || ${res.name} == 'QuestionnaireResponse' || ${res.name} == 'SearchParameter'))
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}">
@ -59,4 +63,4 @@
#end #end
</beans> </beans>

View File

@ -58,13 +58,21 @@ public abstract class BaseJavaConfig${versionCapitalized} extends ca.uhn.fhir.jp
IFhirResourceDaoCodeSystem<org.hl7.fhir.dstu3.model.CodeSystem, org.hl7.fhir.dstu3.model.Coding, org.hl7.fhir.dstu3.model.CodeableConcept> IFhirResourceDaoCodeSystem<org.hl7.fhir.dstu3.model.CodeSystem, org.hl7.fhir.dstu3.model.Coding, org.hl7.fhir.dstu3.model.CodeableConcept>
#elseif ( ${versionCapitalized} == 'R4' && ${res.name} == 'CodeSystem' ) #elseif ( ${versionCapitalized} == 'R4' && ${res.name} == 'CodeSystem' )
IFhirResourceDaoCodeSystem<org.hl7.fhir.r4.model.CodeSystem, org.hl7.fhir.r4.model.Coding, org.hl7.fhir.r4.model.CodeableConcept> IFhirResourceDaoCodeSystem<org.hl7.fhir.r4.model.CodeSystem, org.hl7.fhir.r4.model.Coding, org.hl7.fhir.r4.model.CodeableConcept>
#elseif ( ${versionCapitalized} == 'Dstu3' && ${res.name} == 'ConceptMap' )
IFhirResourceDaoConceptMap<org.hl7.fhir.dstu3.model.ConceptMap>
#elseif ( ${versionCapitalized} == 'R4' && ${res.name} == 'ConceptMap' )
IFhirResourceDaoConceptMap<org.hl7.fhir.r4.model.ConceptMap>
#elseif ( ${versionCapitalized} != 'Dstu1' && ( ${res.name} == 'Encounter' || ${res.name} == 'Everything' || ${res.name} == 'Patient' || ${res.name} == 'Subscription' || ${res.name} == 'SearchParameter')) #elseif ( ${versionCapitalized} != 'Dstu1' && ( ${res.name} == 'Encounter' || ${res.name} == 'Everything' || ${res.name} == 'Patient' || ${res.name} == 'Subscription' || ${res.name} == 'SearchParameter'))
IFhirResourceDao${res.name}<${resourcePackage}.${res.declaringClassNameComplete}> IFhirResourceDao${res.name}<${resourcePackage}.${res.declaringClassNameComplete}>
#else #else
IFhirResourceDao<${resourcePackage}.${res.declaringClassNameComplete}> IFhirResourceDao<${resourcePackage}.${res.declaringClassNameComplete}>
#end #end
dao${res.declaringClassNameComplete}${versionCapitalized}() { dao${res.declaringClassNameComplete}${versionCapitalized}() {
#if ( ${versionCapitalized} != 'Dstu1' && ( ${res.name} == 'Bundle' || ${res.name} == 'Encounter' || ${res.name} == 'Everything' || ${res.name} == 'Patient' || ${res.name} == 'Subscription' || ${res.name} == 'ValueSet' || ${res.name} == 'QuestionnaireResponse' || ${res.name} == 'SearchParameter' || ${res.name} == 'CodeSystem')) #if ( ${versionCapitalized} == 'Dstu3' && ${res.name} == 'ConceptMap' )
ca.uhn.fhir.jpa.dao${package_suffix}.FhirResourceDao${res.name}${versionCapitalized} retVal = new ca.uhn.fhir.jpa.dao${package_suffix}.FhirResourceDao${res.name}${versionCapitalized}();
#elseif ( ${versionCapitalized} == 'R4' && ${res.name} == 'ConceptMap' )
ca.uhn.fhir.jpa.dao${package_suffix}.FhirResourceDao${res.name}${versionCapitalized} retVal = new ca.uhn.fhir.jpa.dao${package_suffix}.FhirResourceDao${res.name}${versionCapitalized}();
#elseif ( ${versionCapitalized} != 'Dstu1' && ( ${res.name} == 'Bundle' || ${res.name} == 'Encounter' || ${res.name} == 'Everything' || ${res.name} == 'Patient' || ${res.name} == 'Subscription' || ${res.name} == 'ValueSet' || ${res.name} == 'QuestionnaireResponse' || ${res.name} == 'SearchParameter' || ${res.name} == 'CodeSystem'))
ca.uhn.fhir.jpa.dao${package_suffix}.FhirResourceDao${res.name}${versionCapitalized} retVal = new ca.uhn.fhir.jpa.dao${package_suffix}.FhirResourceDao${res.name}${versionCapitalized}(); ca.uhn.fhir.jpa.dao${package_suffix}.FhirResourceDao${res.name}${versionCapitalized} retVal = new ca.uhn.fhir.jpa.dao${package_suffix}.FhirResourceDao${res.name}${versionCapitalized}();
#else #else
ca.uhn.fhir.jpa.dao${package_suffix}.FhirResourceDao${versionCapitalized}<${resourcePackage}.${res.declaringClassNameComplete}> retVal = new ca.uhn.fhir.jpa.dao${package_suffix}.FhirResourceDao${versionCapitalized}<${resourcePackage}.${res.declaringClassNameComplete}>(); ca.uhn.fhir.jpa.dao${package_suffix}.FhirResourceDao${versionCapitalized}<${resourcePackage}.${res.declaringClassNameComplete}> retVal = new ca.uhn.fhir.jpa.dao${package_suffix}.FhirResourceDao${versionCapitalized}<${resourcePackage}.${res.declaringClassNameComplete}>();

View File

@ -120,6 +120,10 @@
Fix a bug in the DSTU2 QuestionnaireResponseValidator which prevented validation Fix a bug in the DSTU2 QuestionnaireResponseValidator which prevented validation
on groups with only one question. Thanks David Gileadi for the pull request! on groups with only one question. Thanks David Gileadi for the pull request!
</action> </action>
<action type="add" issue="709">
The <![CDATA[<code>ConceptMap</code>]] operation <![CDATA[<code>$translate</code>]]> has been
implemented.
</action>
</release> </release>
<release version="3.3.0" date="2018-03-29"> <release version="3.3.0" date="2018-03-29">
<action type="add"> <action type="add">
@ -694,7 +698,7 @@ ALTER TABLE hfj_res_ver ALTER COLUMN res_text DROP NOT NULL;</pre>
in FHIR resource (XML/JSON) format. in FHIR resource (XML/JSON) format.
</action> </action>
<action type="add"> <action type="add">
The Binary resource endpoint now supports the `X-Security-Context` header when The Binary resource endpoint now supports the <![CDATA[<code>X-Security-Context</code>]]> header when
reading or writing Binary contents using their native Content-Type (i.e exchanging reading or writing Binary contents using their native Content-Type (i.e exchanging
the raw binary with the server, as opposed to exchanging a FHIR resource). the raw binary with the server, as opposed to exchanging a FHIR resource).
</action> </action>