Merge branch 'master' into ng_20201218_survivorship_poc
This commit is contained in:
commit
82e52750e7
|
@ -32,9 +32,11 @@ import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
|||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
@ -77,9 +79,9 @@ public interface IValidationSupport {
|
|||
* Expands the given portion of a ValueSet
|
||||
*
|
||||
* @param theValidationSupportContext The validation support module will be passed in to this method. This is convenient in cases where the operation needs to make calls to
|
||||
* other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter.
|
||||
* @param theExpansionOptions If provided (may be <code>null</code>), contains options controlling the expansion
|
||||
* @param theValueSetToExpand The valueset that should be expanded
|
||||
* other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter.
|
||||
* @param theExpansionOptions If provided (may be <code>null</code>), contains options controlling the expansion
|
||||
* @param theValueSetToExpand The valueset that should be expanded
|
||||
* @return The expansion, or null
|
||||
*/
|
||||
default ValueSetExpansionOutcome expandValueSet(ValidationSupportContext theValidationSupportContext, @Nullable ValueSetExpansionOptions theExpansionOptions, @Nonnull IBaseResource theValueSetToExpand) {
|
||||
|
@ -116,15 +118,33 @@ public interface IValidationSupport {
|
|||
* Loads a resource needed by the validation (a StructureDefinition, or a
|
||||
* ValueSet)
|
||||
*
|
||||
* @param theClass The type of the resource to load
|
||||
* <p>
|
||||
* Note: Since 5.3.0, {@literal theClass} can be {@literal null}
|
||||
* </p>
|
||||
*
|
||||
* @param theClass The type of the resource to load, or <code>null</code> to return any resource with the given canonical URI
|
||||
* @param theUri The resource URI
|
||||
* @return Returns the resource, or <code>null</code> if no resource with the
|
||||
* given URI can be found
|
||||
*/
|
||||
default <T extends IBaseResource> T fetchResource(Class<T> theClass, String theUri) {
|
||||
Validate.notNull(theClass, "theClass must not be null or blank");
|
||||
@SuppressWarnings("unchecked")
|
||||
default <T extends IBaseResource> T fetchResource(@Nullable Class<T> theClass, String theUri) {
|
||||
Validate.notBlank(theUri, "theUri must not be null or blank");
|
||||
|
||||
if (theClass == null) {
|
||||
Supplier<IBaseResource>[] sources = new Supplier[]{
|
||||
() -> fetchStructureDefinition(theUri),
|
||||
() -> fetchValueSet(theUri),
|
||||
() -> fetchCodeSystem(theUri)
|
||||
};
|
||||
return (T) Arrays
|
||||
.stream(sources)
|
||||
.map(t -> t.get())
|
||||
.filter(t -> t != null)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
switch (getFhirContext().getResourceType(theClass)) {
|
||||
case "StructureDefinition":
|
||||
return theClass.cast(fetchStructureDefinition(theUri));
|
||||
|
@ -150,8 +170,8 @@ public interface IValidationSupport {
|
|||
* or validated
|
||||
*
|
||||
* @param theValidationSupportContext The validation support module will be passed in to this method. This is convenient in cases where the operation needs to make calls to
|
||||
* other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter.
|
||||
* @param theSystem The URI for the code system, e.g. <code>"http://loinc.org"</code>
|
||||
* other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter.
|
||||
* @param theSystem The URI for the code system, e.g. <code>"http://loinc.org"</code>
|
||||
* @return Returns <code>true</code> if codes in the given code system can be
|
||||
* validated
|
||||
*/
|
||||
|
@ -172,11 +192,11 @@ public interface IValidationSupport {
|
|||
* binding fields (e.g. <code>Observation.code</code> in the default profile.
|
||||
*
|
||||
* @param theValidationSupportContext The validation support module will be passed in to this method. This is convenient in cases where the operation needs to make calls to
|
||||
* other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter.
|
||||
* @param theOptions Provides options controlling the validation
|
||||
* @param theCodeSystem The code system, e.g. "<code>http://loinc.org</code>"
|
||||
* @param theCode The code, e.g. "<code>1234-5</code>"
|
||||
* @param theDisplay The display name, if it should also be validated
|
||||
* other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter.
|
||||
* @param theOptions Provides options controlling the validation
|
||||
* @param theCodeSystem The code system, e.g. "<code>http://loinc.org</code>"
|
||||
* @param theCode The code, e.g. "<code>1234-5</code>"
|
||||
* @param theDisplay The display name, if it should also be validated
|
||||
* @return Returns a validation result object
|
||||
*/
|
||||
default CodeValidationResult validateCode(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, String theValueSetUrl) {
|
||||
|
@ -189,11 +209,11 @@ public interface IValidationSupport {
|
|||
* binding fields (e.g. <code>Observation.code</code> in the default profile.
|
||||
*
|
||||
* @param theValidationSupportContext The validation support module will be passed in to this method. This is convenient in cases where the operation needs to make calls to
|
||||
* other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter.
|
||||
* @param theCodeSystem The code system, e.g. "<code>http://loinc.org</code>"
|
||||
* @param theCode The code, e.g. "<code>1234-5</code>"
|
||||
* @param theDisplay The display name, if it should also be validated
|
||||
* @param theValueSet The ValueSet to validate against. Must not be null, and must be a ValueSet resource.
|
||||
* other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter.
|
||||
* @param theCodeSystem The code system, e.g. "<code>http://loinc.org</code>"
|
||||
* @param theCode The code, e.g. "<code>1234-5</code>"
|
||||
* @param theDisplay The display name, if it should also be validated
|
||||
* @param theValueSet The ValueSet to validate against. Must not be null, and must be a ValueSet resource.
|
||||
* @return Returns a validation result object, or <code>null</code> if this validation support module can not handle this kind of request
|
||||
*/
|
||||
default CodeValidationResult validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) {
|
||||
|
@ -204,9 +224,9 @@ public interface IValidationSupport {
|
|||
* Look up a code using the system and code value
|
||||
*
|
||||
* @param theValidationSupportContext The validation support module will be passed in to this method. This is convenient in cases where the operation needs to make calls to
|
||||
* other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter.
|
||||
* @param theSystem The CodeSystem URL
|
||||
* @param theCode The code
|
||||
* other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter.
|
||||
* @param theSystem The CodeSystem URL
|
||||
* @param theCode The code
|
||||
*/
|
||||
default LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode) {
|
||||
return null;
|
||||
|
@ -217,8 +237,8 @@ public interface IValidationSupport {
|
|||
* validation support module
|
||||
*
|
||||
* @param theValidationSupportContext The validation support module will be passed in to this method. This is convenient in cases where the operation needs to make calls to
|
||||
* other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter.
|
||||
* @param theValueSetUrl The ValueSet canonical URL
|
||||
* other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter.
|
||||
* @param theValueSetUrl The ValueSet canonical URL
|
||||
*/
|
||||
default boolean isValueSetSupported(ValidationSupportContext theValidationSupportContext, String theValueSetUrl) {
|
||||
return false;
|
||||
|
@ -228,7 +248,7 @@ public interface IValidationSupport {
|
|||
* Generate a snapshot from the given differential profile.
|
||||
*
|
||||
* @param theValidationSupportContext The validation support module will be passed in to this method. This is convenient in cases where the operation needs to make calls to
|
||||
* other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter.
|
||||
* other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter.
|
||||
* @return Returns null if this module does not know how to handle this request
|
||||
*/
|
||||
default IBaseResource generateSnapshot(ValidationSupportContext theValidationSupportContext, IBaseResource theInput, String theUrl, String theWebUrl, String theProfileName) {
|
||||
|
@ -249,6 +269,25 @@ public interface IValidationSupport {
|
|||
}
|
||||
|
||||
|
||||
enum IssueSeverity {
|
||||
/**
|
||||
* The issue caused the action to fail, and no further checking could be performed.
|
||||
*/
|
||||
FATAL,
|
||||
/**
|
||||
* The issue is sufficiently important to cause the action to fail.
|
||||
*/
|
||||
ERROR,
|
||||
/**
|
||||
* The issue is not important enough to cause the action to fail, but may cause it to be performed suboptimally or in a way that is not as desired.
|
||||
*/
|
||||
WARNING,
|
||||
/**
|
||||
* The issue has no relation to the degree of success of the action.
|
||||
*/
|
||||
INFORMATION
|
||||
}
|
||||
|
||||
class ConceptDesignation {
|
||||
private String myLanguage;
|
||||
private String myUseSystem;
|
||||
|
@ -365,25 +404,6 @@ public interface IValidationSupport {
|
|||
}
|
||||
}
|
||||
|
||||
enum IssueSeverity {
|
||||
/**
|
||||
* The issue caused the action to fail, and no further checking could be performed.
|
||||
*/
|
||||
FATAL,
|
||||
/**
|
||||
* The issue is sufficiently important to cause the action to fail.
|
||||
*/
|
||||
ERROR,
|
||||
/**
|
||||
* The issue is not important enough to cause the action to fail, but may cause it to be performed suboptimally or in a way that is not as desired.
|
||||
*/
|
||||
WARNING,
|
||||
/**
|
||||
* The issue has no relation to the degree of success of the action.
|
||||
*/
|
||||
INFORMATION
|
||||
}
|
||||
|
||||
class CodeValidationResult {
|
||||
private String myCode;
|
||||
private String myMessage;
|
||||
|
|
|
@ -66,6 +66,9 @@ public class ChangelogFilesTest {
|
|||
// this one is optional
|
||||
boolean haveIssue = fieldNames.remove("issue");
|
||||
|
||||
// this one is optional
|
||||
fieldNames.remove("backport");
|
||||
|
||||
assertThat("Invalid element in " + next + ": " + fieldNames, fieldNames, empty());
|
||||
|
||||
if (haveIssue) {
|
||||
|
|
|
@ -32,11 +32,11 @@ import org.apache.commons.io.IOUtils;
|
|||
import org.apache.commons.io.input.CountingInputStream;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.*;
|
||||
import java.util.Date;
|
||||
|
|
|
@ -103,8 +103,6 @@ import org.hl7.fhir.instance.model.api.IBaseParameters;
|
|||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
import org.springframework.data.domain.SliceImpl;
|
||||
|
@ -539,7 +537,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
return myDeleteExpungeService.expungeByResourcePids(theUrl, myResourceName, new SliceImpl<>(ResourcePersistentId.toLongList(theResourceIds)), theTheRequest);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Nonnull
|
||||
@Override
|
||||
public DeleteMethodOutcome deletePidList(String theUrl, Collection<ResourcePersistentId> theResourceIds, DeleteConflictList theDeleteConflicts, RequestDetails theRequest) {
|
||||
StopWatch w = new StopWatch();
|
||||
|
|
|
@ -20,54 +20,34 @@ package ca.uhn.fhir.jpa.dao;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
|
||||
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.lucene.analysis.Analyzer;
|
||||
import org.apache.lucene.analysis.TokenStream;
|
||||
import org.apache.lucene.search.highlight.Formatter;
|
||||
import org.apache.lucene.search.highlight.Highlighter;
|
||||
import org.apache.lucene.search.highlight.Scorer;
|
||||
import org.apache.lucene.search.highlight.TextFragment;
|
||||
import org.apache.lucene.search.highlight.TokenGroup;
|
||||
import org.hibernate.search.backend.lucene.index.LuceneIndexManager;
|
||||
import org.hibernate.search.engine.search.predicate.dsl.BooleanPredicateClausesStep;
|
||||
import org.hibernate.search.engine.search.predicate.dsl.SearchPredicateFactory;
|
||||
import org.hibernate.search.engine.search.query.SearchQuery;
|
||||
import org.hibernate.search.mapper.orm.Search;
|
||||
import org.hibernate.search.mapper.orm.mapping.SearchMapping;
|
||||
import org.hibernate.search.mapper.orm.session.SearchSession;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
import javax.persistence.PersistenceContextType;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -76,20 +56,20 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||
|
||||
public class FulltextSearchSvcImpl implements IFulltextSearchSvc {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FulltextSearchSvcImpl.class);
|
||||
|
||||
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
|
||||
private EntityManager myEntityManager;
|
||||
|
||||
@Autowired
|
||||
private PlatformTransactionManager myTxManager;
|
||||
|
||||
@Autowired
|
||||
protected IForcedIdDao myForcedIdDao;
|
||||
|
||||
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
|
||||
private EntityManager myEntityManager;
|
||||
@Autowired
|
||||
private PlatformTransactionManager myTxManager;
|
||||
@Autowired
|
||||
private IdHelperService myIdHelperService;
|
||||
|
||||
private Boolean ourDisabled;
|
||||
@Autowired
|
||||
private IRequestPartitionHelperSvc myRequestPartitionHelperService;
|
||||
@Autowired
|
||||
private PartitionSettings myPartitionSettings;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -98,28 +78,28 @@ public class FulltextSearchSvcImpl implements IFulltextSearchSvc {
|
|||
super();
|
||||
}
|
||||
|
||||
private void addTextSearch(SearchPredicateFactory f, BooleanPredicateClausesStep<?> b, List<List<IQueryParameterType>> theTerms, String theFieldName, String theFieldNameEdgeNGram, String theFieldNameTextNGram){
|
||||
private void addTextSearch(SearchPredicateFactory f, BooleanPredicateClausesStep<?> b, List<List<IQueryParameterType>> theTerms, String theFieldName, String theFieldNameEdgeNGram, String theFieldNameTextNGram) {
|
||||
if (theTerms == null) {
|
||||
return;
|
||||
}
|
||||
for (List<? extends IQueryParameterType> nextAnd : theTerms) {
|
||||
Set<String> terms = extractOrStringParams(nextAnd);
|
||||
if (terms.size() == 1) {
|
||||
b.must(f.phrase()
|
||||
.field(theFieldName)
|
||||
.boost(4.0f)
|
||||
.matching(terms.iterator().next().toLowerCase())
|
||||
.slop(2));
|
||||
} else if (terms.size() > 1){
|
||||
String joinedTerms = StringUtils.join(terms, ' ');
|
||||
b.must(f.match().field(theFieldName).matching(joinedTerms));
|
||||
} else {
|
||||
ourLog.debug("No Terms found in query parameter {}", nextAnd);
|
||||
}
|
||||
if (terms.size() == 1) {
|
||||
b.must(f.phrase()
|
||||
.field(theFieldName)
|
||||
.boost(4.0f)
|
||||
.matching(terms.iterator().next().toLowerCase())
|
||||
.slop(2));
|
||||
} else if (terms.size() > 1) {
|
||||
String joinedTerms = StringUtils.join(terms, ' ');
|
||||
b.must(f.match().field(theFieldName).matching(joinedTerms));
|
||||
} else {
|
||||
ourLog.debug("No Terms found in query parameter {}", nextAnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Nonnull
|
||||
private Set<String> extractOrStringParams(List<? extends IQueryParameterType> nextAnd) {
|
||||
Set<String> terms = new HashSet<>();
|
||||
for (IQueryParameterType nextOr : nextAnd) {
|
||||
|
@ -229,10 +209,4 @@ public class FulltextSearchSvcImpl implements IFulltextSearchSvc {
|
|||
return doSearch(theResourceName, theParams, null);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private IRequestPartitionHelperSvc myRequestPartitionHelperService;
|
||||
|
||||
@Autowired
|
||||
private PartitionSettings myPartitionSettings;
|
||||
|
||||
}
|
||||
|
|
|
@ -46,9 +46,12 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.transaction.Transactional;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
|
@ -104,110 +107,13 @@ public class JpaPersistedResourceValidationSupport implements IValidationSupport
|
|||
|
||||
@Override
|
||||
@SuppressWarnings({"unchecked", "unused"})
|
||||
public <T extends IBaseResource> T fetchResource(Class<T> theClass, String theUri) {
|
||||
public <T extends IBaseResource> T fetchResource(@Nullable Class<T> theClass, String theUri) {
|
||||
if (isBlank(theUri)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String key = theClass.getSimpleName() + " " + theUri;
|
||||
IBaseResource fetched = myLoadCache.get(key, t -> {
|
||||
IdType id = new IdType(theUri);
|
||||
boolean localReference = false;
|
||||
if (id.hasBaseUrl() == false && id.hasIdPart() == true) {
|
||||
localReference = true;
|
||||
}
|
||||
|
||||
String resourceName = myFhirContext.getResourceType(theClass);
|
||||
IBundleProvider search;
|
||||
switch (resourceName) {
|
||||
case "ValueSet":
|
||||
if (localReference) {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(IAnyResource.SP_RES_ID, new StringParam(theUri));
|
||||
search = myDaoRegistry.getResourceDao(resourceName).search(params);
|
||||
if (search.size() == 0) {
|
||||
params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(ValueSet.SP_URL, new UriParam(theUri));
|
||||
search = myDaoRegistry.getResourceDao(resourceName).search(params);
|
||||
}
|
||||
} else {
|
||||
int versionSeparator = theUri.lastIndexOf('|');
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
if (versionSeparator != -1) {
|
||||
params.add(ValueSet.SP_VERSION, new TokenParam(theUri.substring(versionSeparator + 1)));
|
||||
params.add(ValueSet.SP_URL, new UriParam(theUri.substring(0, versionSeparator)));
|
||||
} else {
|
||||
params.add(ValueSet.SP_URL, new UriParam(theUri));
|
||||
}
|
||||
params.setSort(new SortSpec("_lastUpdated").setOrder(SortOrderEnum.DESC));
|
||||
search = myDaoRegistry.getResourceDao(resourceName).search(params);
|
||||
}
|
||||
break;
|
||||
case "StructureDefinition": {
|
||||
// Don't allow the core FHIR definitions to be overwritten
|
||||
if (theUri.startsWith("http://hl7.org/fhir/StructureDefinition/")) {
|
||||
String typeName = theUri.substring("http://hl7.org/fhir/StructureDefinition/".length());
|
||||
if (myFhirContext.getElementDefinition(typeName) != null) {
|
||||
return myNoMatch;
|
||||
}
|
||||
}
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(StructureDefinition.SP_URL, new UriParam(theUri));
|
||||
search = myDaoRegistry.getResourceDao("StructureDefinition").search(params);
|
||||
break;
|
||||
}
|
||||
case "Questionnaire": {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
if (localReference || myFhirContext.getVersion().getVersion().isEquivalentTo(FhirVersionEnum.DSTU2)) {
|
||||
params.add(IAnyResource.SP_RES_ID, new StringParam(id.getIdPart()));
|
||||
} else {
|
||||
params.add(Questionnaire.SP_URL, new UriParam(id.getValue()));
|
||||
}
|
||||
search = myDaoRegistry.getResourceDao("Questionnaire").search(params);
|
||||
break;
|
||||
}
|
||||
case "CodeSystem": {
|
||||
int versionSeparator = theUri.lastIndexOf('|');
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
if (versionSeparator != -1) {
|
||||
params.add(CodeSystem.SP_VERSION, new TokenParam(theUri.substring(versionSeparator + 1)));
|
||||
params.add(CodeSystem.SP_URL, new UriParam(theUri.substring(0, versionSeparator)));
|
||||
} else {
|
||||
params.add(CodeSystem.SP_URL, new UriParam(theUri));
|
||||
}
|
||||
params.setSort(new SortSpec("_lastUpdated").setOrder(SortOrderEnum.DESC));
|
||||
search = myDaoRegistry.getResourceDao(resourceName).search(params);
|
||||
break;
|
||||
}
|
||||
case "ImplementationGuide":
|
||||
case "SearchParameter": {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(ImplementationGuide.SP_URL, new UriParam(theUri));
|
||||
search = myDaoRegistry.getResourceDao(resourceName).search(params);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException("Can't fetch resource type: " + resourceName);
|
||||
}
|
||||
|
||||
Integer size = search.size();
|
||||
if (size == null || size == 0) {
|
||||
return myNoMatch;
|
||||
}
|
||||
|
||||
if (size > 1) {
|
||||
ourLog.warn("Found multiple {} instances with URL search value of: {}", resourceName, theUri);
|
||||
}
|
||||
|
||||
return search.getResources(0, 1).get(0);
|
||||
});
|
||||
String key = theClass + " " + theUri;
|
||||
IBaseResource fetched = myLoadCache.get(key, t -> doFetchResource(theClass, theUri));
|
||||
|
||||
if (fetched == myNoMatch) {
|
||||
return null;
|
||||
|
@ -216,6 +122,119 @@ public class JpaPersistedResourceValidationSupport implements IValidationSupport
|
|||
return (T) fetched;
|
||||
}
|
||||
|
||||
private <T extends IBaseResource> IBaseResource doFetchResource(@Nullable Class<T> theClass, String theUri) {
|
||||
if (theClass == null) {
|
||||
Supplier<IBaseResource>[] fetchers = new Supplier[]{
|
||||
() -> doFetchResource(ValueSet.class, theUri),
|
||||
() -> doFetchResource(CodeSystem.class, theUri),
|
||||
() -> doFetchResource(StructureDefinition.class, theUri)
|
||||
};
|
||||
return Arrays
|
||||
.stream(fetchers)
|
||||
.map(t -> t.get())
|
||||
.filter(t -> t != myNoMatch)
|
||||
.findFirst()
|
||||
.orElse(myNoMatch);
|
||||
}
|
||||
|
||||
IdType id = new IdType(theUri);
|
||||
boolean localReference = false;
|
||||
if (id.hasBaseUrl() == false && id.hasIdPart() == true) {
|
||||
localReference = true;
|
||||
}
|
||||
|
||||
String resourceName = myFhirContext.getResourceType(theClass);
|
||||
IBundleProvider search;
|
||||
switch (resourceName) {
|
||||
case "ValueSet":
|
||||
if (localReference) {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(IAnyResource.SP_RES_ID, new StringParam(theUri));
|
||||
search = myDaoRegistry.getResourceDao(resourceName).search(params);
|
||||
if (search.size() == 0) {
|
||||
params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(ValueSet.SP_URL, new UriParam(theUri));
|
||||
search = myDaoRegistry.getResourceDao(resourceName).search(params);
|
||||
}
|
||||
} else {
|
||||
int versionSeparator = theUri.lastIndexOf('|');
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
if (versionSeparator != -1) {
|
||||
params.add(ValueSet.SP_VERSION, new TokenParam(theUri.substring(versionSeparator + 1)));
|
||||
params.add(ValueSet.SP_URL, new UriParam(theUri.substring(0, versionSeparator)));
|
||||
} else {
|
||||
params.add(ValueSet.SP_URL, new UriParam(theUri));
|
||||
}
|
||||
params.setSort(new SortSpec("_lastUpdated").setOrder(SortOrderEnum.DESC));
|
||||
search = myDaoRegistry.getResourceDao(resourceName).search(params);
|
||||
}
|
||||
break;
|
||||
case "StructureDefinition": {
|
||||
// Don't allow the core FHIR definitions to be overwritten
|
||||
if (theUri.startsWith("http://hl7.org/fhir/StructureDefinition/")) {
|
||||
String typeName = theUri.substring("http://hl7.org/fhir/StructureDefinition/".length());
|
||||
if (myFhirContext.getElementDefinition(typeName) != null) {
|
||||
return myNoMatch;
|
||||
}
|
||||
}
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(StructureDefinition.SP_URL, new UriParam(theUri));
|
||||
search = myDaoRegistry.getResourceDao("StructureDefinition").search(params);
|
||||
break;
|
||||
}
|
||||
case "Questionnaire": {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
if (localReference || myFhirContext.getVersion().getVersion().isEquivalentTo(FhirVersionEnum.DSTU2)) {
|
||||
params.add(IAnyResource.SP_RES_ID, new StringParam(id.getIdPart()));
|
||||
} else {
|
||||
params.add(Questionnaire.SP_URL, new UriParam(id.getValue()));
|
||||
}
|
||||
search = myDaoRegistry.getResourceDao("Questionnaire").search(params);
|
||||
break;
|
||||
}
|
||||
case "CodeSystem": {
|
||||
int versionSeparator = theUri.lastIndexOf('|');
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
if (versionSeparator != -1) {
|
||||
params.add(CodeSystem.SP_VERSION, new TokenParam(theUri.substring(versionSeparator + 1)));
|
||||
params.add(CodeSystem.SP_URL, new UriParam(theUri.substring(0, versionSeparator)));
|
||||
} else {
|
||||
params.add(CodeSystem.SP_URL, new UriParam(theUri));
|
||||
}
|
||||
params.setSort(new SortSpec("_lastUpdated").setOrder(SortOrderEnum.DESC));
|
||||
search = myDaoRegistry.getResourceDao(resourceName).search(params);
|
||||
break;
|
||||
}
|
||||
case "ImplementationGuide":
|
||||
case "SearchParameter": {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(ImplementationGuide.SP_URL, new UriParam(theUri));
|
||||
search = myDaoRegistry.getResourceDao(resourceName).search(params);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException("Can't fetch resource type: " + resourceName);
|
||||
}
|
||||
|
||||
Integer size = search.size();
|
||||
if (size == null || size == 0) {
|
||||
return myNoMatch;
|
||||
}
|
||||
|
||||
if (size > 1) {
|
||||
ourLog.warn("Found multiple {} instances with URL search value of: {}", resourceName, theUri);
|
||||
}
|
||||
|
||||
return search.getResources(0, 1).get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FhirContext getFhirContext() {
|
||||
return myFhirContext;
|
||||
|
|
|
@ -29,9 +29,10 @@ import ca.uhn.fhir.rest.server.provider.ProviderConstants;
|
|||
import ca.uhn.fhir.util.ParametersUtil;
|
||||
import org.hl7.fhir.instance.model.api.IBaseParameters;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import static ca.uhn.fhir.jpa.partition.PartitionLookupSvcImpl.validatePartitionIdSupplied;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
import static org.hl7.fhir.instance.model.api.IPrimitiveType.toValueOrNull;
|
||||
|
@ -151,7 +152,7 @@ public class PartitionManagementProvider {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Nonnull
|
||||
private PartitionEntity parseInput(@OperationParam(name = ProviderConstants.PARTITION_MANAGEMENT_PARTITION_ID, min = 1, max = 1, typeName = "integer") IPrimitiveType<Integer> thePartitionId, @OperationParam(name = ProviderConstants.PARTITION_MANAGEMENT_PARTITION_NAME, min = 1, max = 1, typeName = "code") IPrimitiveType<String> thePartitionName, @OperationParam(name = ProviderConstants.PARTITION_MANAGEMENT_PARTITION_DESC, min = 0, max = 1, typeName = "string") IPrimitiveType<String> thePartitionDescription) {
|
||||
PartitionEntity input = new PartitionEntity();
|
||||
if (thePartitionId != null) {
|
||||
|
|
|
@ -52,7 +52,6 @@ import ca.uhn.fhir.rest.api.server.SimplePreResourceShowDetails;
|
|||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
@ -191,7 +190,7 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Nonnull
|
||||
private RequestPartitionId getRequestPartitionId() {
|
||||
if (myRequestPartitionId == null) {
|
||||
if (mySearchEntity.getResourceId() != null) {
|
||||
|
|
|
@ -576,7 +576,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
return null;
|
||||
}
|
||||
|
||||
@org.jetbrains.annotations.Nullable
|
||||
@Nullable
|
||||
private Integer getLoadSynchronousUpToOrNull(CacheControlDirective theCacheControlDirective) {
|
||||
final Integer loadSynchronousUpTo;
|
||||
if (theCacheControlDirective != null && theCacheControlDirective.isNoStore()) {
|
||||
|
|
|
@ -32,13 +32,13 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
|||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.elementmodel.JsonParser;
|
||||
import org.hl7.fhir.r5.model.CanonicalResource;
|
||||
import org.hl7.fhir.r5.utils.IResourceValidator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
public class ValidatorResourceFetcher implements IResourceValidator.IValidatorResourceFetcher {
|
||||
|
@ -61,7 +61,6 @@ public class ValidatorResourceFetcher implements IResourceValidator.IValidatorRe
|
|||
}
|
||||
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Override
|
||||
public Element fetch(Object appContext, String theUrl) throws FHIRException {
|
||||
|
||||
|
@ -94,13 +93,13 @@ public class ValidatorResourceFetcher implements IResourceValidator.IValidatorRe
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean resolveURL(Object appContext, String path, String url) throws IOException, FHIRException {
|
||||
public boolean resolveURL(Object appContext, String path, String url, String type) throws FHIRException {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] fetchRaw(String url) throws IOException {
|
||||
return new byte[0];
|
||||
public byte[] fetchRaw(String url) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -108,4 +107,14 @@ public class ValidatorResourceFetcher implements IResourceValidator.IValidatorRe
|
|||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public CanonicalResource fetchCanonicalResource(String url) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fetchesCanonicalResource(String url) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -144,7 +144,7 @@ public class FhirResourceDaoDstu2ValidateTest extends BaseJpaDstu2Test {
|
|||
} catch (PreconditionFailedException e) {
|
||||
String ooString = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(e.getOperationOutcome());
|
||||
ourLog.info(ooString);
|
||||
assertThat(ooString, containsString("Profile reference 'http://example.com/StructureDefinition/testValidateResourceContainingProfileDeclarationInvalid' could not be resolved, so has not been checked"));
|
||||
assertThat(ooString, containsString("Profile reference 'http://example.com/StructureDefinition/testValidateResourceContainingProfileDeclarationInvalid' has not been checked because it is unknown"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -333,7 +333,7 @@ public class FhirResourceDaoDstu3ValidateTest extends BaseJpaDstu3Test {
|
|||
OperationOutcome oo = (OperationOutcome) e.getOperationOutcome();
|
||||
String outputString = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(oo);
|
||||
ourLog.info(outputString);
|
||||
assertThat(outputString, containsString("Profile reference 'http://example.com/StructureDefinition/testValidateResourceContainingProfileDeclarationInvalid' could not be resolved, so has not been checked"));
|
||||
assertThat(outputString, containsString("Profile reference 'http://example.com/StructureDefinition/testValidateResourceContainingProfileDeclarationInvalid' has not been checked because it is unknown"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1138,7 +1138,7 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
|
|||
org.hl7.fhir.r4.model.OperationOutcome oo = (org.hl7.fhir.r4.model.OperationOutcome) e.getOperationOutcome();
|
||||
String outputString = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(oo);
|
||||
ourLog.info(outputString);
|
||||
assertThat(outputString, containsString("Profile reference 'http://example.com/StructureDefinition/testValidateResourceContainingProfileDeclarationInvalid' could not be resolved, so has not been checked"));
|
||||
assertThat(outputString, containsString("Profile reference 'http://example.com/StructureDefinition/testValidateResourceContainingProfileDeclarationInvalid' has not been checked because it is unknown"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1174,7 +1174,7 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
|
|||
org.hl7.fhir.r4.model.OperationOutcome oo = (org.hl7.fhir.r4.model.OperationOutcome) e.getOperationOutcome();
|
||||
String outputString = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(oo);
|
||||
ourLog.info(outputString);
|
||||
assertThat(outputString, containsString("Profile reference 'http://example.com/StructureDefinition/testValidateResourceContainingProfileDeclarationInvalid' could not be resolved, so has not been checked"));
|
||||
assertThat(outputString, containsString("Profile reference 'http://example.com/StructureDefinition/testValidateResourceContainingProfileDeclarationInvalid' has not been checked because it is unknown"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@ import org.hl7.fhir.r4.model.CodeType;
|
|||
import org.hl7.fhir.r4.model.IntegerType;
|
||||
import org.hl7.fhir.r4.model.Parameters;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -28,6 +27,8 @@ import org.springframework.context.annotation.Configuration;
|
|||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
|
@ -87,7 +88,7 @@ public class PartitionManagementProviderTest {
|
|||
assertEquals("a description", ((StringType) response.getParameter(ProviderConstants.PARTITION_MANAGEMENT_PARTITION_DESC)).getValue());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Nonnull
|
||||
private Parameters createInputPartition() {
|
||||
Parameters input = new Parameters();
|
||||
input.addParameter(ProviderConstants.PARTITION_MANAGEMENT_PARTITION_ID, new IntegerType(123));
|
||||
|
@ -248,7 +249,7 @@ public class PartitionManagementProviderTest {
|
|||
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Nonnull
|
||||
private static Answer<Object> createAnswer() {
|
||||
return t -> t.getArgument(0, PartitionEntity.class);
|
||||
}
|
||||
|
|
|
@ -2403,7 +2403,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
String respString = IOUtils.toString(resp.getEntity().getContent(), Charsets.UTF_8);
|
||||
ourLog.info(respString);
|
||||
assertEquals(412, resp.getStatusLine().getStatusCode());
|
||||
assertThat(respString, containsString("Profile reference 'http://foo/structuredefinition/myprofile' could not be resolved, so has not been checked"));
|
||||
assertThat(respString, containsString("Profile reference 'http://foo/structuredefinition/myprofile' has not been checked because it is unknown"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import static java.time.temporal.ChronoUnit.SECONDS;
|
|||
public class TestElasticsearchContainerHelper {
|
||||
|
||||
|
||||
public static final String ELASTICSEARCH_VERSION = "7.10.0";
|
||||
public static final String ELASTICSEARCH_VERSION = "7.10.2";
|
||||
public static final String ELASTICSEARCH_IMAGE = "docker.elastic.co/elasticsearch/elasticsearch:" + ELASTICSEARCH_VERSION;
|
||||
|
||||
public static ElasticsearchContainer getEmbeddedElasticSearch() {
|
||||
|
|
|
@ -20,23 +20,23 @@ package ca.uhn.fhir.jpa.mdm.svc;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||
import ca.uhn.fhir.mdm.api.IGoldenResourceMergerSvc;
|
||||
import ca.uhn.fhir.mdm.api.IMdmControllerSvc;
|
||||
import ca.uhn.fhir.mdm.api.IMdmLinkQuerySvc;
|
||||
import ca.uhn.fhir.mdm.api.IMdmLinkUpdaterSvc;
|
||||
import ca.uhn.fhir.mdm.api.IGoldenResourceMergerSvc;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkJson;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||
import ca.uhn.fhir.mdm.provider.MdmControllerHelper;
|
||||
import ca.uhn.fhir.mdm.provider.MdmControllerUtil;
|
||||
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,23 +20,23 @@ package ca.uhn.fhir.jpa.mdm.svc;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.mdm.api.MdmConstants;
|
||||
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
||||
import ca.uhn.fhir.jpa.model.entity.TagTypeEnum;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
||||
import ca.uhn.fhir.mdm.api.MdmConstants;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
|
@ -60,10 +60,11 @@ public class MdmResourceDaoSvc {
|
|||
}
|
||||
|
||||
/**
|
||||
* Given a resource, remove its Golden Resource tag.
|
||||
* @param theGoldenResource the {@link IAnyResource} to remove the tag from.
|
||||
* @param theResourcetype the type of that resource
|
||||
*/
|
||||
* Given a resource, remove its Golden Resource tag.
|
||||
*
|
||||
* @param theGoldenResource the {@link IAnyResource} to remove the tag from.
|
||||
* @param theResourcetype the type of that resource
|
||||
*/
|
||||
public void removeGoldenResourceTag(IAnyResource theGoldenResource, String theResourcetype) {
|
||||
IFhirResourceDao resourceDao = myDaoRegistry.getResourceDao(theResourcetype);
|
||||
resourceDao.removeTag(theGoldenResource.getIdElement(), TagTypeEnum.TAG, MdmConstants.SYSTEM_GOLDEN_RECORD_STATUS, MdmConstants.CODE_GOLDEN_RECORD);
|
||||
|
@ -99,7 +100,7 @@ public class MdmResourceDaoSvc {
|
|||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Nonnull
|
||||
private SearchParameterMap buildEidSearchParameterMap(String theTheEid) {
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.setLoadSynchronous(true);
|
||||
|
|
|
@ -48,7 +48,6 @@ import org.hl7.fhir.r4.model.Organization;
|
|||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Practitioner;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
@ -431,7 +430,7 @@ abstract public class BaseMdmR4Test extends BaseJpaR4Test {
|
|||
return getPatientsByTag(MdmConstants.CODE_GOLDEN_RECORD_REDIRECTED);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Nonnull
|
||||
private List<IBaseResource> getPatientsByTag(String theCode) {
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.setLoadSynchronous(true);
|
||||
|
|
|
@ -23,7 +23,8 @@ package ca.uhn.fhir.jpa.migrate.taskdef;
|
|||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public abstract class BaseTableColumnTypeTask extends BaseTableColumnTask {
|
||||
private ColumnTypeEnum myColumnType;
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.apache.http.client.methods.CloseableHttpResponse;
|
|||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.Coding;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -95,6 +96,19 @@ public class FhirPathFilterInterceptorTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilteredResponse_ExpressionReturnsExtension() throws IOException {
|
||||
createPatient();
|
||||
|
||||
HttpGet request = new HttpGet(myPatientId + "?_fhirpath=Patient.extension('http://hl7.org/fhir/us/core/StructureDefinition/us-core-race')&_pretty=true");
|
||||
try (CloseableHttpResponse response = myHttpClient.execute(request)) {
|
||||
String responseText = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8);
|
||||
ourLog.info("Response:\n{}", responseText);
|
||||
assertThat(responseText, containsString("\"url\": \"http://hl7.org/fhir/us/core/StructureDefinition/us-core-race\""));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilteredResponse_ExpressionReturnsResource() throws IOException {
|
||||
createPatient();
|
||||
|
@ -159,6 +173,11 @@ public class FhirPathFilterInterceptorTest {
|
|||
|
||||
private void createPatient() {
|
||||
Patient p = new Patient();
|
||||
p.addExtension()
|
||||
.setUrl("http://hl7.org/fhir/us/core/StructureDefinition/us-core-race")
|
||||
.addExtension()
|
||||
.setUrl("ombCategory")
|
||||
.setValue(new Coding("urn:oid:2.16.840.1.113883.6.238", "2106-3", "White"));
|
||||
p.setActive(true);
|
||||
p.addIdentifier().setSystem("http://identifiers/1").setValue("value-1");
|
||||
p.addIdentifier().setSystem("http://identifiers/2").setValue("value-2");
|
||||
|
|
|
@ -107,7 +107,7 @@
|
|||
</dependency>
|
||||
|
||||
<!--
|
||||
Optional dependencies used by org.hl7.fhir.r4
|
||||
Optional dependencies used by org.hl7.fhir.r5
|
||||
We include these here to get the aggregate JavaDoc to work
|
||||
-->
|
||||
<dependency>
|
||||
|
@ -133,6 +133,11 @@
|
|||
<artifactId>gson</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Testing -->
|
||||
<dependency>
|
||||
|
@ -181,12 +186,12 @@
|
|||
<artifactId>thymeleaf</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-test-utilities</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-test-utilities</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Dependencies for Schematron -->
|
||||
<dependency>
|
||||
|
@ -209,16 +214,6 @@
|
|||
<artifactId>jaxb-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>com.sun.xml.bind</groupId>-->
|
||||
<!--<artifactId>jaxb-core</artifactId>-->
|
||||
<!--<scope>test</scope>-->
|
||||
<!--</dependency>-->
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>com.sun.xml.bind</groupId>-->
|
||||
<!--<artifactId>jaxb-impl</artifactId>-->
|
||||
<!--<scope>test</scope>-->
|
||||
<!--</dependency>-->
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-runtime</artifactId>
|
||||
|
@ -344,13 +339,13 @@
|
|||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<_nouses>true</_nouses>
|
||||
<_removeheaders>Built-By, Include-Resource, Private-Package, Require-Capability</_removeheaders>
|
||||
<!-- No need to disable normal OSGi class loading
|
||||
<Fragment-Host>
|
||||
ca.uhn.hapi.fhir.hapi-fhir-base
|
||||
</Fragment-Host>
|
||||
-->
|
||||
<_nouses>true</_nouses>
|
||||
<_removeheaders>Built-By, Include-Resource, Private-Package, Require-Capability</_removeheaders>
|
||||
<!-- No need to disable normal OSGi class loading
|
||||
<Fragment-Host>
|
||||
ca.uhn.hapi.fhir.hapi-fhir-base
|
||||
</Fragment-Host>
|
||||
-->
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -287,6 +287,11 @@ public final class HapiWorkerContext extends I18nBase implements IWorkerContext
|
|||
return myCtx.getVersion().getVersion().getFhirVersionString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSpecUrl() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UcumService getUcumService() {
|
||||
throw new UnsupportedOperationException();
|
||||
|
@ -302,6 +307,11 @@ public final class HapiWorkerContext extends I18nBase implements IWorkerContext
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getCodeSystemsUsed() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TranslationServices translator() {
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
@ -30,9 +30,9 @@ public class FhirPathR5 implements IFhirPath {
|
|||
result = myEngine.evaluate((Base) theInput, thePath);
|
||||
} catch (FHIRException e) {
|
||||
throw new FhirPathExecutionException(e);
|
||||
}
|
||||
}
|
||||
|
||||
for (Base next : result) {
|
||||
for (Base next : result) {
|
||||
if (!theReturnType.isAssignableFrom(next.getClass())) {
|
||||
throw new FhirPathExecutionException("FluentPath expression \"" + thePath + "\" returned unexpected type " + next.getClass().getSimpleName() + " - Expected " + theReturnType.getName());
|
||||
}
|
||||
|
|
|
@ -6,14 +6,13 @@ import ca.uhn.fhir.context.support.IValidationSupport;
|
|||
import ca.uhn.fhir.context.support.ValidationSupportContext;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -64,8 +63,8 @@ public class CachingValidationSupport extends BaseValidationSupportWrapper imple
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(Class<T> theClass, String theUri) {
|
||||
return loadFromCache(myCache, "fetchResource " + theClass.getName() + " " + theUri,
|
||||
public <T extends IBaseResource> T fetchResource(@Nullable Class<T> theClass, String theUri) {
|
||||
return loadFromCache(myCache, "fetchResource " + theClass + " " + theUri,
|
||||
t -> super.fetchResource(theClass, theUri));
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta
|
|||
private boolean noExtensibleWarnings = false;
|
||||
private boolean noBindingMsgSuppressed = false;
|
||||
private volatile VersionSpecificWorkerContextWrapper myWrappedWorkerContext;
|
||||
private boolean errorForUnknownProfiles;
|
||||
private boolean errorForUnknownProfiles = true;
|
||||
private boolean assumeValidRestReferences;
|
||||
private List<String> myExtensionDomains = Collections.emptyList();
|
||||
private IResourceValidator.IValidatorResourceFetcher validatorResourceFetcher;
|
||||
|
|
|
@ -61,6 +61,9 @@ public class HapiToHl7OrgDstu2ValidatingSupportWrapper extends BaseValidationSup
|
|||
}
|
||||
|
||||
private Class<? extends IBaseResource> translateTypeToHapi(Class<? extends IBaseResource> theCodeSystemType) {
|
||||
if (theCodeSystemType == null) {
|
||||
return null;
|
||||
}
|
||||
String resName = getFhirContext().getResourceType(theCodeSystemType);
|
||||
return myHapiCtx.getResourceDefinition(resName).getImplementingClass();
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.hl7.fhir.r5.elementmodel.Manager;
|
|||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathEngine;
|
||||
import org.hl7.fhir.r5.utils.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.XVerExtensionManager;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.validation.instance.InstanceValidator;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -103,8 +104,9 @@ class ValidatorWrapper {
|
|||
public List<ValidationMessage> validate(IWorkerContext theWorkerContext, IValidationContext<?> theValidationContext) {
|
||||
InstanceValidator v;
|
||||
FHIRPathEngine.IEvaluationContext evaluationCtx = new FhirInstanceValidator.NullEvaluationContext();
|
||||
XVerExtensionManager xverManager = new XVerExtensionManager(theWorkerContext);
|
||||
try {
|
||||
v = new InstanceValidator(theWorkerContext, evaluationCtx);
|
||||
v = new InstanceValidator(theWorkerContext, evaluationCtx, xverManager);
|
||||
} catch (Exception e) {
|
||||
throw new ConfigurationException(e);
|
||||
}
|
||||
|
@ -193,7 +195,12 @@ class ValidatorWrapper {
|
|||
i--;
|
||||
}
|
||||
|
||||
if (message.endsWith("' could not be resolved, so has not been checked") && next.getLevel() == ValidationMessage.IssueSeverity.WARNING) {
|
||||
if (
|
||||
myErrorForUnknownProfiles &&
|
||||
next.getLevel() == ValidationMessage.IssueSeverity.WARNING &&
|
||||
message.contains("Profile reference '") &&
|
||||
message.contains("' has not been checked because it is unknown")
|
||||
) {
|
||||
next.setLevel(ValidationMessage.IssueSeverity.ERROR);
|
||||
}
|
||||
|
||||
|
|
|
@ -81,13 +81,15 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
|
|||
fetchResourceName = "ValueSet";
|
||||
}
|
||||
}
|
||||
Class<? extends IBaseResource> fetchResourceType = myValidationSupportContext.getRootValidationSupport().getFhirContext().getResourceDefinition(fetchResourceName).getImplementingClass();
|
||||
IBaseResource fetched = myValidationSupportContext.getRootValidationSupport().fetchResource(fetchResourceType, key.getUri());
|
||||
|
||||
if (fetched == null) {
|
||||
return null;
|
||||
Class<? extends IBaseResource> fetchResourceType;
|
||||
if (fetchResourceName.equals("Resource")) {
|
||||
fetchResourceType = null;
|
||||
} else {
|
||||
fetchResourceType = myValidationSupportContext.getRootValidationSupport().getFhirContext().getResourceDefinition(fetchResourceName).getImplementingClass();
|
||||
}
|
||||
|
||||
IBaseResource fetched = myValidationSupportContext.getRootValidationSupport().fetchResource(fetchResourceType, key.getUri());
|
||||
|
||||
Resource canonical = myModelConverter.toCanonical(fetched);
|
||||
|
||||
|
@ -425,6 +427,11 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
|
|||
return myValidationSupportContext.getRootValidationSupport().getFhirContext().getVersion().getVersion().getFhirVersionString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSpecUrl() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCache() {
|
||||
throw new UnsupportedOperationException();
|
||||
|
@ -440,6 +447,11 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getCodeSystemsUsed() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<org.hl7.fhir.r5.model.StructureMap> listTransforms() {
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
@ -664,6 +664,8 @@ public class FhirInstanceValidatorDstu3Test {
|
|||
} else if (t.getMessage().contains("ValueSet as a URI SHALL start with http:// or https:// or urn:")) {
|
||||
// Some DSTU3 structures have missing binding information
|
||||
return false;
|
||||
} else if (t.getMessage().contains("The valueSet reference http://www.rfc-editor.org/bcp/bcp13.txt on element")) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
@ -1135,7 +1137,7 @@ public class FhirInstanceValidatorDstu3Test {
|
|||
myInstanceVal.setValidationSupport(myValidationSupport);
|
||||
ValidationResult output = myVal.validateWithResult(input);
|
||||
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
|
||||
assertThat(errors.toString(), containsString("Profile reference 'http://foo/structuredefinition/myprofile' could not be resolved, so has not been checked"));
|
||||
assertThat(errors.toString(), containsString("Profile reference 'http://foo/structuredefinition/myprofile' has not been checked because it is unknown"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1314,7 +1316,7 @@ public class FhirInstanceValidatorDstu3Test {
|
|||
myInstanceVal.setValidatorResourceFetcher(resourceFetcher);
|
||||
myVal.validateWithResult(input);
|
||||
|
||||
verify(resourceFetcher, times(3)).resolveURL(any(), anyString(), anyString());
|
||||
verify(resourceFetcher, times(3)).resolveURL(any(), anyString(), anyString(), anyString());
|
||||
verify(resourceFetcher, times(4)).validationPolicy(any(), anyString(), anyString());
|
||||
verify(resourceFetcher, times(4)).fetch(any(), anyString());
|
||||
}
|
||||
|
|
|
@ -254,7 +254,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
errors = myVal.validateWithResult(qa);
|
||||
errors = stripBindingHasNoSourceMessage(errors);
|
||||
ourLog.info(errors.toString());
|
||||
assertThat(errors.toString(), containsString("Unknown code: http://codesystems.com/system / code1 - QuestionnaireResponse.item[0].answer[0].value.ofType(Coding)"));
|
||||
assertThat(errors.toString(), containsString("Unknown code: http://codesystems.com/system / code1 for 'http://codesystems.com/system#code1'"));
|
||||
assertThat(errors.toString(), containsString("QuestionnaireResponse.item[0].answer[0]"));
|
||||
|
||||
// Unhandled system
|
||||
|
|
|
@ -1152,7 +1152,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
|
|||
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
|
||||
|
||||
assertEquals(1, errors.size());
|
||||
assertEquals("Profile reference 'http://foo/structuredefinition/myprofile' could not be resolved, so has not been checked", errors.get(0).getMessage());
|
||||
assertEquals("Profile reference 'http://foo/structuredefinition/myprofile' has not been checked because it is unknown", errors.get(0).getMessage());
|
||||
assertEquals(ResultSeverityEnum.ERROR, errors.get(0).getSeverity());
|
||||
}
|
||||
|
||||
|
@ -1402,7 +1402,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
|
|||
myInstanceVal.setValidatorResourceFetcher(resourceFetcher);
|
||||
myVal.validateWithResult(encoded);
|
||||
|
||||
verify(resourceFetcher, times(15)).resolveURL(any(), anyString(), anyString());
|
||||
verify(resourceFetcher, times(15)).resolveURL(any(), anyString(), anyString(), anyString());
|
||||
verify(resourceFetcher, times(12)).validationPolicy(any(), anyString(), anyString());
|
||||
verify(resourceFetcher, times(12)).fetch(any(), anyString());
|
||||
}
|
||||
|
|
|
@ -432,8 +432,8 @@ public class FhirInstanceValidatorR5Test {
|
|||
myInstanceVal.setValidatorResourceFetcher(resourceFetcher);
|
||||
myVal.validateWithResult(input);
|
||||
|
||||
verify(resourceFetcher, times(13)).resolveURL(any(), anyString(), anyString());
|
||||
verify(resourceFetcher, times(3)).validationPolicy(any(), anyString(), anyString());
|
||||
verify(resourceFetcher, times(13)).resolveURL(any(), anyString(), anyString(), anyString());
|
||||
verify(resourceFetcher, times(4)).validationPolicy(any(), anyString(), anyString());
|
||||
verify(resourceFetcher, times(3)).fetch(any(), anyString());
|
||||
}
|
||||
|
||||
|
@ -794,7 +794,7 @@ public class FhirInstanceValidatorR5Test {
|
|||
myInstanceVal.setValidationSupport(myValidationSupport);
|
||||
ValidationResult output = myVal.validateWithResult(input);
|
||||
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
|
||||
assertThat(errors.toString(), containsString("Profile reference 'http://foo/structuredefinition/myprofile' could not be resolved, so has not been checked"));
|
||||
assertThat(errors.toString(), containsString("Profile reference 'http://foo/structuredefinition/myprofile' has not been checked because it is unknown"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
4
pom.xml
4
pom.xml
|
@ -712,7 +712,7 @@
|
|||
|
||||
<properties>
|
||||
|
||||
<fhir_core_version>5.2.0</fhir_core_version>
|
||||
<fhir_core_version>5.2.16</fhir_core_version>
|
||||
<ucum_version>1.0.3</ucum_version>
|
||||
|
||||
<surefire_jvm_args>-Dfile.encoding=UTF-8 -Xmx2048m</surefire_jvm_args>
|
||||
|
@ -1462,7 +1462,7 @@
|
|||
<dependency>
|
||||
<groupId>org.elasticsearch.client</groupId>
|
||||
<artifactId>elasticsearch-rest-high-level-client</artifactId>
|
||||
<version>7.10.0</version>
|
||||
<version>7.10.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.search</groupId>
|
||||
|
|
Loading…
Reference in New Issue