Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
36f81731be
|
@ -33,7 +33,7 @@ public interface IRestfulClient extends IBasicClient {
|
|||
|
||||
/**
|
||||
* The "@Search" annotation indicates that this method supports the
|
||||
* search operation. You may have many different method annotated with
|
||||
* search operation. You may have many different methods annotated with
|
||||
* this annotation, to support many different search criteria. This
|
||||
* example searches by family name.
|
||||
*
|
||||
|
|
|
@ -55,7 +55,7 @@ public class RestfulObservationResourceProvider implements IResourceProvider {
|
|||
|
||||
/**
|
||||
* The "@Search" annotation indicates that this method supports the
|
||||
* search operation. You may have many different method annotated with
|
||||
* search operation. You may have many different methods annotated with
|
||||
* this annotation, to support many different search criteria. This
|
||||
* example searches by family name.
|
||||
*
|
||||
|
|
|
@ -56,7 +56,7 @@ public class RestfulPatientResourceProvider implements IResourceProvider {
|
|||
|
||||
/**
|
||||
* The "@Search" annotation indicates that this method supports the
|
||||
* search operation. You may have many different method annotated with
|
||||
* search operation. You may have many different methods annotated with
|
||||
* this annotation, to support many different search criteria. This
|
||||
* example searches by family name.
|
||||
*
|
||||
|
|
|
@ -234,6 +234,12 @@ public class ValidatorExamples {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet fetchValueSet(FhirContext theContext, String theSystem) {
|
||||
// TODO: implement
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||
// TODO: implement
|
||||
|
|
|
@ -19,10 +19,14 @@ package ca.uhn.fhir.rest.annotation;
|
|||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
import java.lang.annotation.*;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Denotes a parameter for a REST method which will contain the resource actually
|
||||
* Denotes a parameter for a REST method which will contain the resource actually
|
||||
* being created/updated/etc in an operation which contains a resource in the HTTP request.
|
||||
* <p>
|
||||
* For example, in a {@link Create} operation the method parameter annotated with this
|
||||
|
@ -32,7 +36,7 @@ import java.lang.annotation.*;
|
|||
* Parameters with this annotation should typically be of the type of resource being
|
||||
* operated on (see below for an exception when raw data is required). For example, in a
|
||||
* IResourceProvider for Patient resources, the parameter annotated with this
|
||||
* annotation should be of type Patient.
|
||||
* annotation should be of type Patient.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that in servers it is also acceptable to have parameters with this annotation
|
||||
|
@ -41,8 +45,11 @@ import java.lang.annotation.*;
|
|||
* have multiple parameters with this annotation, so you can have one parameter
|
||||
* which accepts the parsed resource, and another which accepts the raw request.
|
||||
* </p>
|
||||
* <p>
|
||||
* Also note that this parameter may be null if a client does not supply a body.
|
||||
* </p>
|
||||
*/
|
||||
@Target(value=ElementType.PARAMETER)
|
||||
@Target(value = ElementType.PARAMETER)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ResourceParam {
|
||||
|
||||
|
|
|
@ -217,28 +217,20 @@ public class PortUtil {
|
|||
}
|
||||
|
||||
private static boolean isAvailable(int port) {
|
||||
ServerSocket ss = null;
|
||||
DatagramSocket ds = null;
|
||||
try {
|
||||
ss = new ServerSocket(port);
|
||||
ourLog.info("Testing a bind on port {}", port);
|
||||
try (ServerSocket ss = new ServerSocket(port)) {
|
||||
ss.setReuseAddress(true);
|
||||
ds = new DatagramSocket(port);
|
||||
ds.setReuseAddress(true);
|
||||
return true;
|
||||
try (DatagramSocket ds = new DatagramSocket(port)) {
|
||||
ds.setReuseAddress(true);
|
||||
ourLog.info("Successfully bound port {}", port);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
ourLog.info("Failed to bind port {}: {}", port, e.toString());
|
||||
return false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
ourLog.info("Failed to bind port {}: {}", port, e.toString());
|
||||
return false;
|
||||
} finally {
|
||||
if (ds != null) {
|
||||
ds.close();
|
||||
}
|
||||
|
||||
if (ss != null) {
|
||||
try {
|
||||
ss.close();
|
||||
} catch (IOException e) {
|
||||
/* should not be thrown */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -89,6 +89,7 @@ ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.failedToCreateWithClientAssignedIdNo
|
|||
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.invalidParameterChain=Invalid parameter chain: {0}
|
||||
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.invalidVersion=Version "{0}" is not valid for resource {1}
|
||||
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.multipleParamsWithSameNameOneIsMissingTrue=This server does not know how to handle multiple "{0}" parameters where one has a value of :missing=true
|
||||
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.missingBody=No body was supplied in request
|
||||
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.unableToDeleteNotFound=Unable to find resource matching URL "{0}". Deletion failed.
|
||||
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.successfulCreate=Successfully created resource "{0}" in {1}ms
|
||||
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.successfulUpdate=Successfully updated resource "{0}" in {1}ms
|
||||
|
|
|
@ -63,13 +63,23 @@ public class PortUtilTest {
|
|||
for (int j = 0; j < portsPerTaskCount; j++) {
|
||||
int nextFreePort = portUtil.getNextFreePort();
|
||||
|
||||
boolean bound;
|
||||
try (ServerSocket ss = new ServerSocket()) {
|
||||
ss.bind(new InetSocketAddress("localhost", nextFreePort));
|
||||
bound = true;
|
||||
} catch (IOException e) {
|
||||
String msg = "Failure binding new port " + nextFreePort + ": " + e.toString();
|
||||
ourLog.error(msg, e);
|
||||
errors.add(msg);
|
||||
bound = false;
|
||||
}
|
||||
|
||||
if (!bound) {
|
||||
try (ServerSocket ss = new ServerSocket()) {
|
||||
Thread.sleep(1000);
|
||||
ss.bind(new InetSocketAddress("localhost", nextFreePort));
|
||||
} catch (Exception e) {
|
||||
String msg = "Failure binding new port (second attempt) " + nextFreePort + ": " + e.toString();
|
||||
ourLog.error(msg, e);
|
||||
errors.add(msg);
|
||||
}
|
||||
}
|
||||
|
||||
ports.add(nextFreePort);
|
||||
|
|
|
@ -27,6 +27,7 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
|||
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||
import org.hl7.fhir.dstu3.model.StructureDefinition;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
@ -56,6 +57,11 @@ public class LoadingValidationSupportDstu3 implements IValidationSupport {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet fetchValueSet(FhirContext theContext, String theSystem) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||
String resName = myCtx.getResourceDefinition(theClass).getName();
|
||||
|
|
|
@ -27,6 +27,7 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
|||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.CodeSystem;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r4.terminologies.ValueSetExpander;
|
||||
|
||||
|
@ -58,6 +59,11 @@ public class LoadingValidationSupportR4 implements org.hl7.fhir.r4.hapi.ctx.IVal
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet fetchValueSet(FhirContext theContext, String theSystem) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||
String resName = myCtx.getResourceDefinition(theClass).getName();
|
||||
|
|
|
@ -67,6 +67,11 @@ public class IgPackValidationSupportDstu3 implements IValidationSupport {
|
|||
return fetchResource(theContext, CodeSystem.class, theSystem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet fetchValueSet(FhirContext theContext, String theSystem) {
|
||||
return fetchResource(theContext, ValueSet.class, theSystem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||
for (Map.Entry<IIdType, IBaseResource> next : myIgResources.entrySet()) {
|
||||
|
|
|
@ -73,14 +73,17 @@ public abstract class BaseConfig implements SchedulingConfigurer {
|
|||
@Autowired
|
||||
protected Environment myEnv;
|
||||
|
||||
@Autowired
|
||||
protected DaoRegistry myDaoRegistry;
|
||||
|
||||
@Override
|
||||
public void configureTasks(@Nonnull ScheduledTaskRegistrar theTaskRegistrar) {
|
||||
theTaskRegistrar.setTaskScheduler(taskScheduler());
|
||||
}
|
||||
|
||||
@Bean("myDaoRegistry")
|
||||
public DaoRegistry daoRegistry() {
|
||||
return new DaoRegistry();
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public DatabaseBackedPagingProvider databaseBackedPagingProvider() {
|
||||
return new DatabaseBackedPagingProvider();
|
||||
|
@ -182,7 +185,7 @@ public abstract class BaseConfig implements SchedulingConfigurer {
|
|||
* Subclasses may override
|
||||
*/
|
||||
protected boolean isSupported(String theResourceType) {
|
||||
return myDaoRegistry.getResourceDao(theResourceType) != null;
|
||||
return daoRegistry().getResourceDao(theResourceType) != null;
|
||||
}
|
||||
|
||||
public static void configureEntityManagerFactory(LocalContainerEntityManagerFactoryBean theFactory, FhirContext theCtx) {
|
||||
|
|
|
@ -142,6 +142,11 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
|
||||
@Override
|
||||
public DaoMethodOutcome create(T theResource, String theIfNoneExist, boolean thePerformIndexing, Date theUpdateTimestamp, RequestDetails theRequestDetails) {
|
||||
if (theResource == null) {
|
||||
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "missingBody");
|
||||
throw new InvalidRequestException(msg);
|
||||
}
|
||||
|
||||
if (isNotBlank(theResource.getIdElement().getIdPart())) {
|
||||
if (getContext().getVersion().getVersion().isOlderThan(FhirVersionEnum.DSTU3)) {
|
||||
String message = getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "failedToCreateWithClientAssignedId", theResource.getIdElement().getIdPart());
|
||||
|
@ -1270,6 +1275,11 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
|
||||
@Override
|
||||
public DaoMethodOutcome update(T theResource, String theMatchUrl, boolean thePerformIndexing, boolean theForceUpdateVersion, RequestDetails theRequestDetails) {
|
||||
if (theResource == null) {
|
||||
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "missingBody");
|
||||
throw new InvalidRequestException(msg);
|
||||
}
|
||||
|
||||
StopWatch w = new StopWatch();
|
||||
|
||||
preProcessResourceForStorage(theResource);
|
||||
|
|
|
@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.dao;
|
|||
* 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.
|
||||
|
@ -35,13 +35,20 @@ import org.springframework.stereotype.Component;
|
|||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component("myDaoRegistry")
|
||||
public class DaoRegistry implements ApplicationContextAware {
|
||||
private ApplicationContext myAppCtx;
|
||||
|
||||
@Autowired
|
||||
private FhirContext myContext;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public DaoRegistry() {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
private volatile Map<String, IFhirResourceDao<?>> myResourceNameToResourceDao;
|
||||
private volatile IFhirSystemDao<?, ?> mySystemDao;
|
||||
private Set<String> mySupportedResourceTypes;
|
||||
|
|
|
@ -89,6 +89,14 @@ public class JpaValidationSupportDstu3 implements IJpaValidationSupportDstu3, Ap
|
|||
return fetchResource(theCtx, CodeSystem.class, theSystem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet fetchValueSet(FhirContext theCtx, String theSystem) {
|
||||
if (isBlank(theSystem)) {
|
||||
return null;
|
||||
}
|
||||
return fetchResource(theCtx, ValueSet.class, theSystem);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||
|
|
|
@ -87,7 +87,7 @@ public class SearchParamWithInlineReferencesExtractor {
|
|||
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
|
||||
protected EntityManager myEntityManager;
|
||||
|
||||
public void populateFromResource(ResourceIndexedSearchParams theParams, IDao theCallingDao, Date theUpdateTime, ResourceTable theEntity, IBaseResource theResource, ResourceIndexedSearchParams existingParams) {
|
||||
public void populateFromResource(ResourceIndexedSearchParams theParams, IDao theCallingDao, Date theUpdateTime, ResourceTable theEntity, IBaseResource theResource, ResourceIndexedSearchParams theExistingParams) {
|
||||
mySearchParamExtractorService.extractFromResource(theParams, theEntity, theResource);
|
||||
|
||||
Set<Map.Entry<String, RuntimeSearchParam>> activeSearchParams = mySearchParamRegistry.getActiveSearchParams(theEntity.getResourceType()).entrySet();
|
||||
|
@ -104,7 +104,7 @@ public class SearchParamWithInlineReferencesExtractor {
|
|||
/*
|
||||
* If the existing resource already has links and those match links we still want, use them instead of removing them and re adding them
|
||||
*/
|
||||
for (Iterator<ResourceLink> existingLinkIter = existingParams.getResourceLinks().iterator(); existingLinkIter.hasNext(); ) {
|
||||
for (Iterator<ResourceLink> existingLinkIter = theExistingParams.getResourceLinks().iterator(); existingLinkIter.hasNext(); ) {
|
||||
ResourceLink nextExisting = existingLinkIter.next();
|
||||
if (theParams.myLinks.remove(nextExisting)) {
|
||||
existingLinkIter.remove();
|
||||
|
@ -263,6 +263,7 @@ public class SearchParamWithInlineReferencesExtractor {
|
|||
myEntityManager.remove(next);
|
||||
theEntity.getParamsCompositeStringUnique().remove(next);
|
||||
}
|
||||
boolean haveNewParams = false;
|
||||
for (ResourceIndexedCompositeStringUnique next : myDaoSearchParamSynchronizer.subtract(theParams.myCompositeStringUniques, existingParams.myCompositeStringUniques)) {
|
||||
if (myDaoConfig.isUniqueIndexesCheckedBeforeSave()) {
|
||||
ResourceIndexedCompositeStringUnique existing = myResourceIndexedCompositeStringUniqueDao.findByQueryString(next.getIndexString());
|
||||
|
@ -273,6 +274,12 @@ public class SearchParamWithInlineReferencesExtractor {
|
|||
}
|
||||
ourLog.debug("Persisting unique index: {}", next);
|
||||
myEntityManager.persist(next);
|
||||
haveNewParams = true;
|
||||
}
|
||||
if (theParams.myCompositeStringUniques.size() > 0 || haveNewParams) {
|
||||
theEntity.setParamsCompositeStringUniquePresent(true);
|
||||
} else {
|
||||
theEntity.setParamsCompositeStringUniquePresent(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,6 +86,11 @@ public class JpaValidationSupportR4 implements IJpaValidationSupportR4, Applicat
|
|||
return fetchResource(theCtx, CodeSystem.class, theSystem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet fetchValueSet(FhirContext theCtx, String theSystem) {
|
||||
return fetchResource(theCtx, ValueSet.class, theSystem);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||
|
|
|
@ -204,6 +204,12 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvcImpl implemen
|
|||
return null;
|
||||
}
|
||||
|
||||
@CoverageIgnore
|
||||
@Override
|
||||
public ValueSet fetchValueSet(FhirContext theContext, String theSystem) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||
return null;
|
||||
|
|
|
@ -155,6 +155,12 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvcImpl implements
|
|||
return null;
|
||||
}
|
||||
|
||||
@CoverageIgnore
|
||||
@Override
|
||||
public ValueSet fetchValueSet(FhirContext theContext, String theSystem) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||
return null;
|
||||
|
|
|
@ -887,6 +887,7 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
|
|||
* Select the version from HFJ_RES_VER
|
||||
* Select the current token indexes
|
||||
*/
|
||||
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
|
||||
assertEquals(3, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
|
||||
assertEquals(0, myCaptureQueriesListener.countDeleteQueriesForCurrentThread());
|
||||
assertEquals(1, myCaptureQueriesListener.countInsertQueriesForCurrentThread()); // Add an entry to HFJ_RES_VER
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
|
@ -33,7 +35,9 @@ import javax.annotation.Nonnull;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.INDEX_STATUS_INDEXED;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
@ -503,7 +507,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
assertThat(toUnqualifiedVersionlessIdValues(outcome), containsInAnyOrder(srId));
|
||||
unformattedSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, false);
|
||||
assertThat(unformattedSql, stringContainsInOrder(
|
||||
"IDX_STRING='ServiceRequest?identifier=sys%7C111&patient=Patient%2F" + ptId.getIdPart() + "&performer=Practitioner%2F"+ practId.getIdPart() +"'",
|
||||
"IDX_STRING='ServiceRequest?identifier=sys%7C111&patient=Patient%2F" + ptId.getIdPart() + "&performer=Practitioner%2F" + practId.getIdPart() + "'",
|
||||
"HASH_SYS_AND_VALUE in ('6795110643554413877')"
|
||||
));
|
||||
assertThat(unformattedSql, not(containsString(("RES_DELETED_AT"))));
|
||||
|
@ -773,11 +777,23 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
// The third pass has a low of (Coverage.lastUpdated + 1ms)
|
||||
assertEquals(0, myResourceReindexingSvc.forceReindexingPass());
|
||||
|
||||
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
ourLog.info("** Uniques: {}", uniques);
|
||||
assertEquals(uniques.toString(), 1, uniques.size());
|
||||
assertEquals("Coverage/" + id3.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
||||
assertEquals("Coverage?beneficiary=Patient%2F" + id2.getIdPart() + "&identifier=urn%3Afoo%3Abar%7C123", uniques.get(0).getIndexString());
|
||||
runInTransaction(() -> {
|
||||
List<ResourceTable> tables = myResourceTableDao.findAll();
|
||||
String resourceIds = tables.stream().map(t -> t.getIdDt().getValue()).collect(Collectors.joining(", "));
|
||||
// 1 patient, 1 coverage, 3 search parameters
|
||||
assertEquals(resourceIds, 5, tables.size());
|
||||
for (int i = 0; i < tables.size(); i++) {
|
||||
assertEquals(INDEX_STATUS_INDEXED, tables.get(i).getIndexStatus().intValue());
|
||||
}
|
||||
});
|
||||
|
||||
runInTransaction(() -> {
|
||||
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
ourLog.info("** Uniques: {}", uniques);
|
||||
assertEquals(uniques.toString(), 1, uniques.size());
|
||||
assertEquals("Coverage/" + id3.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
||||
assertEquals("Coverage?beneficiary=Patient%2F" + id2.getIdPart() + "&identifier=urn%3Afoo%3Abar%7C123", uniques.get(0).getIndexString());
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -8,7 +8,9 @@ import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
|||
import ca.uhn.fhir.jpa.searchparam.extractor.PathAndRef;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorR4;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport;
|
||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
|
@ -34,6 +36,7 @@ public class SearchParamExtractorR4Test {
|
|||
|
||||
@Before
|
||||
public void before() {
|
||||
|
||||
mySearchParamRegistry = new ISearchParamRegistry() {
|
||||
@Override
|
||||
public void forceRefresh() {
|
||||
|
@ -52,11 +55,12 @@ public class SearchParamExtractorR4Test {
|
|||
|
||||
@Override
|
||||
public Map<String, RuntimeSearchParam> getActiveSearchParams(String theResourceName) {
|
||||
RuntimeResourceDefinition nextResDef = ourCtx.getResourceDefinition(theResourceName);
|
||||
Map<String, RuntimeSearchParam> sps = new HashMap<>();
|
||||
RuntimeResourceDefinition nextResDef = ourCtx.getResourceDefinition(theResourceName);
|
||||
for (RuntimeSearchParam nextSp : nextResDef.getSearchParams()) {
|
||||
sps.put(nextSp.getName(), nextSp);
|
||||
}
|
||||
|
||||
return sps;
|
||||
}
|
||||
|
||||
|
@ -130,6 +134,21 @@ public class SearchParamExtractorR4Test {
|
|||
assertEquals("Consent/999", ((Reference) links.get(0).getRef()).getReference());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testExtensionContainingReference() {
|
||||
String path = "Patient.extension('http://patext').value.as(Reference)";
|
||||
|
||||
RuntimeSearchParam sp = new RuntimeSearchParam("extpat", "Patient SP", path, RestSearchParameterTypeEnum.REFERENCE, new HashSet<>(), Sets.newHashSet("Patient"), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE);
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addExtension("http://patext", new Reference("Organization/AAA"));
|
||||
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new ModelConfig(), ourCtx, ourValidationSupport, mySearchParamRegistry);
|
||||
List<PathAndRef> links = extractor.extractResourceLinks(patient, sp);
|
||||
assertEquals(1, links.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractComponentQuantities() {
|
||||
Observation o1 = new Observation();
|
||||
|
|
|
@ -267,6 +267,84 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithDeepChain() throws IOException {
|
||||
|
||||
SearchParameter sp = new SearchParameter();
|
||||
sp.addBase("Patient");
|
||||
sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||
sp.setType(Enumerations.SearchParamType.REFERENCE);
|
||||
sp.setCode("extpatorg");
|
||||
sp.setName("extpatorg");
|
||||
sp.setExpression("Patient.extension('http://patext').value.as(Reference)");
|
||||
ourClient.create().resource(sp).execute();
|
||||
|
||||
sp = new SearchParameter();
|
||||
sp.addBase("Organization");
|
||||
sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||
sp.setType(Enumerations.SearchParamType.REFERENCE);
|
||||
sp.setCode("extorgorg");
|
||||
sp.setName("extorgorg");
|
||||
sp.setExpression("Organization.extension('http://orgext').value.as(Reference)");
|
||||
ourClient.create().resource(sp).execute();
|
||||
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Organization grandParent = new Organization();
|
||||
grandParent.setName("GRANDPARENT");
|
||||
IIdType grandParentId = ourClient.create().resource(grandParent).execute().getId().toUnqualifiedVersionless();
|
||||
|
||||
Organization parent = new Organization();
|
||||
parent.setName("PARENT");
|
||||
parent.getPartOf().setReference(grandParentId.getValue());
|
||||
parent.addExtension("http://orgext", new Reference().setReference(grandParentId.getValue()));
|
||||
IIdType parentId = ourClient.create().resource(parent).execute().getId().toUnqualifiedVersionless();
|
||||
|
||||
Organization org = new Organization();
|
||||
org.setName("ORGANIZATION");
|
||||
org.getPartOf().setReference(parentId.getValue());
|
||||
org.addExtension("http://orgext", new Reference().setReference(parentId.getValue()));
|
||||
IIdType orgId = ourClient.create().resource(org).execute().getId().toUnqualifiedVersionless();
|
||||
|
||||
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
|
||||
myCaptureQueriesListener.clear();
|
||||
|
||||
Patient p = new Patient();
|
||||
p.getManagingOrganization().setReference(orgId.getValue());
|
||||
p.addExtension("http://patext", new Reference().setReference(orgId.getValue()));
|
||||
String pid = ourClient.create().resource(p).execute().getId().toUnqualified().getValue();
|
||||
|
||||
List<String> idValues;
|
||||
|
||||
// Regular search param
|
||||
idValues = searchAndReturnUnqualifiedIdValues(ourServerBase + "/Patient?organization=" + orgId.getValue());
|
||||
assertThat(idValues, contains(pid));
|
||||
|
||||
idValues = searchAndReturnUnqualifiedIdValues(ourServerBase + "/Patient?organization.name=ORGANIZATION");
|
||||
assertThat(idValues, contains(pid));
|
||||
|
||||
idValues = searchAndReturnUnqualifiedIdValues(ourServerBase + "/Patient?organization.partof.name=PARENT");
|
||||
assertThat(idValues, contains(pid));
|
||||
|
||||
idValues = searchAndReturnUnqualifiedIdValues(ourServerBase + "/Patient?organization.partof.partof.name=GRANDPARENT");
|
||||
assertThat(idValues, contains(pid));
|
||||
|
||||
// Search param on extension
|
||||
myCaptureQueriesListener.clear();
|
||||
idValues = searchAndReturnUnqualifiedIdValues(ourServerBase + "/Patient?extpatorg=" + orgId.getValue());
|
||||
myCaptureQueriesListener.logSelectQueries();
|
||||
assertThat(idValues, contains(pid));
|
||||
|
||||
idValues = searchAndReturnUnqualifiedIdValues(ourServerBase + "/Patient?extpatorg.name=ORGANIZATION");
|
||||
assertThat(idValues, contains(pid));
|
||||
|
||||
idValues = searchAndReturnUnqualifiedIdValues(ourServerBase + "/Patient?extpatorg.extorgorg.name=PARENT");
|
||||
assertThat(idValues, contains(pid));
|
||||
|
||||
idValues = searchAndReturnUnqualifiedIdValues(ourServerBase + "/Patient?extpatorg.extorgorg.extorgorg.name=GRANDPARENT");
|
||||
assertThat(idValues, contains(pid));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchFetchPageBeyondEnd() {
|
||||
|
@ -319,6 +397,38 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithNoBody() throws IOException {
|
||||
|
||||
HttpPut httpPost = new HttpPut(ourServerBase + "/Patient/AAA");
|
||||
try (CloseableHttpResponse status = ourHttpClient.execute(httpPost)) {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(status.getStatusLine().toString());
|
||||
ourLog.info(responseContent);
|
||||
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, containsString("No body was supplied in request"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreateWithNoBody() throws IOException {
|
||||
|
||||
HttpPost httpPost = new HttpPost(ourServerBase + "/Patient");
|
||||
try (CloseableHttpResponse status = ourHttpClient.execute(httpPost)) {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(status.getStatusLine().toString());
|
||||
ourLog.info(responseContent);
|
||||
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, containsString("No body was supplied in request"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Before
|
||||
public void beforeDisableResultReuse() {
|
||||
|
@ -398,7 +508,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
@Test
|
||||
@Ignore
|
||||
public void test() throws IOException {
|
||||
HttpGet get = new HttpGet(ourServerBase + "/QuestionnaireResponse?_count=50&status=completed&questionnaire=ARIncenterAbsRecord&_lastUpdated=%3E"+UrlUtil.escapeUrlParam("=2018-01-01")+"&context.organization=O3435");
|
||||
HttpGet get = new HttpGet(ourServerBase + "/QuestionnaireResponse?_count=50&status=completed&questionnaire=ARIncenterAbsRecord&_lastUpdated=%3E" + UrlUtil.escapeUrlParam("=2018-01-01") + "&context.organization=O3435");
|
||||
ourLog.info("*** MAKING QUERY");
|
||||
ourHttpClient.execute(get);
|
||||
System.exit(0);
|
||||
|
@ -549,7 +659,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
Binary fromDB = ourClient.read().resource(Binary.class).withId(resource.toVersionless()).execute();
|
||||
assertEquals("1", fromDB.getIdElement().getVersionIdPart());
|
||||
|
||||
arr[ 0 ] = 2;
|
||||
arr[0] = 2;
|
||||
HttpPut putRequest = new HttpPut(ourServerBase + "/Binary/" + resource.getIdPart());
|
||||
putRequest.setEntity(new ByteArrayEntity(arr, ContentType.parse("dansk")));
|
||||
CloseableHttpResponse resp = ourHttpClient.execute(putRequest);
|
||||
|
@ -563,7 +673,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
fromDB = ourClient.read().resource(Binary.class).withId(resource.toVersionless()).execute();
|
||||
assertEquals("2", fromDB.getIdElement().getVersionIdPart());
|
||||
|
||||
arr[ 0 ] = 3;
|
||||
arr[0] = 3;
|
||||
fromDB.setContent(arr);
|
||||
String encoded = myFhirCtx.newJsonParser().encodeResourceToString(fromDB);
|
||||
putRequest = new HttpPut(ourServerBase + "/Binary/" + resource.getIdPart());
|
||||
|
@ -581,7 +691,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
|
||||
// Now an update with the wrong ID in the body
|
||||
|
||||
arr[ 0 ] = 4;
|
||||
arr[0] = 4;
|
||||
binary.setId("");
|
||||
encoded = myFhirCtx.newJsonParser().encodeResourceToString(binary);
|
||||
putRequest = new HttpPut(ourServerBase + "/Binary/" + resource.getIdPart());
|
||||
|
@ -635,12 +745,13 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
ourClient.registerInterceptor(new IClientInterceptor() {
|
||||
@Override
|
||||
public void interceptRequest(IHttpRequest theRequest) {
|
||||
theRequest.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RETURN + "=" + Constants.HEADER_PREFER_RETURN_OPERATION_OUTCOME);
|
||||
theRequest.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RETURN + "=" + Constants.HEADER_PREFER_RETURN_OPERATION_OUTCOME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interceptResponse(IHttpResponse theResponse) { // TODO Auto-generated method stu
|
||||
public void interceptResponse(IHttpResponse theResponse) { // TODO Auto-generated method stu
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
try {
|
||||
// Missing status, which is mandatory
|
||||
|
@ -837,7 +948,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
response.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreateResourceReturnsOperationOutcome() throws IOException {
|
||||
String resource = "<Patient xmlns=\"http://hl7.org/fhir\"></Patient>";
|
||||
|
@ -1193,7 +1304,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
|
||||
// String response = "";
|
||||
StringBuilder b = new StringBuilder();
|
||||
char[] buf = new char[ 1000 ];
|
||||
char[] buf = new char[1000];
|
||||
while (socketInput.read(buf) != -1) {
|
||||
b.append(buf);
|
||||
}
|
||||
|
@ -5194,7 +5305,6 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
}
|
||||
|
||||
|
||||
|
||||
private String toStr(Date theDate) {
|
||||
return new InstantDt(theDate).getValueAsString();
|
||||
}
|
||||
|
|
|
@ -24,6 +24,9 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.IInterceptorBroadcaster;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.jpa.model.search.PerformanceMessage;
|
||||
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.searchparam.retry.Retrier;
|
||||
|
@ -41,6 +44,7 @@ import org.springframework.scheduling.annotation.Scheduled;
|
|||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
|
@ -63,6 +67,9 @@ public abstract class BaseSearchParamRegistry<SP extends IBaseResource> implemen
|
|||
private volatile Map<String, Map<String, RuntimeSearchParam>> myActiveSearchParams;
|
||||
private volatile long myLastRefresh;
|
||||
|
||||
@Autowired
|
||||
private IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||
|
||||
@Override
|
||||
public RuntimeSearchParam getActiveSearchParam(String theResourceName, String theParamName) {
|
||||
|
||||
|
@ -121,6 +128,7 @@ public abstract class BaseSearchParamRegistry<SP extends IBaseResource> implemen
|
|||
}
|
||||
|
||||
private void populateActiveSearchParams(Map<String, Map<String, RuntimeSearchParam>> theActiveSearchParams) {
|
||||
|
||||
Map<String, List<JpaRuntimeSearchParam>> activeUniqueSearchParams = new HashMap<>();
|
||||
Map<String, Map<Set<String>, List<JpaRuntimeSearchParam>>> activeParamNamesToUniqueSearchParams = new HashMap<>();
|
||||
|
||||
|
@ -133,8 +141,13 @@ public abstract class BaseSearchParamRegistry<SP extends IBaseResource> implemen
|
|||
for (Map.Entry<String, Map<String, RuntimeSearchParam>> nextResourceNameToEntries : theActiveSearchParams.entrySet()) {
|
||||
List<JpaRuntimeSearchParam> uniqueSearchParams = activeUniqueSearchParams.computeIfAbsent(nextResourceNameToEntries.getKey(), k -> new ArrayList<>());
|
||||
Collection<RuntimeSearchParam> nextSearchParamsForResourceName = nextResourceNameToEntries.getValue().values();
|
||||
|
||||
ourLog.trace("Resource {} has {} params", nextResourceNameToEntries.getKey(), nextResourceNameToEntries.getValue().size());
|
||||
|
||||
for (RuntimeSearchParam nextCandidate : nextSearchParamsForResourceName) {
|
||||
|
||||
ourLog.trace("Resource {} has parameter {} with ID {}", nextResourceNameToEntries.getKey(), nextCandidate.getName(), nextCandidate.getId());
|
||||
|
||||
if (nextCandidate.getId() != null) {
|
||||
idToRuntimeSearchParam.put(nextCandidate.getId().toUnqualifiedVersionless().getValue(), nextCandidate);
|
||||
}
|
||||
|
@ -150,6 +163,8 @@ public abstract class BaseSearchParamRegistry<SP extends IBaseResource> implemen
|
|||
|
||||
}
|
||||
|
||||
ourLog.trace("Have {} search params loaded", idToRuntimeSearchParam.size());
|
||||
|
||||
Set<String> haveSeen = new HashSet<>();
|
||||
for (JpaRuntimeSearchParam next : jpaSearchParams) {
|
||||
if (!haveSeen.add(next.getId().toUnqualifiedVersionless().getValue())) {
|
||||
|
@ -164,7 +179,14 @@ public abstract class BaseSearchParamRegistry<SP extends IBaseResource> implemen
|
|||
next.getCompositeOf().add(componentTarget);
|
||||
paramNames.add(componentTarget.getName());
|
||||
} else {
|
||||
ourLog.warn("Search parameter {} refers to unknown component {}", next.getId().toUnqualifiedVersionless().getValue(), nextRef);
|
||||
String existingParams = idToRuntimeSearchParam
|
||||
.keySet()
|
||||
.stream()
|
||||
.sorted()
|
||||
.collect(Collectors.joining(", "));
|
||||
String message = "Search parameter " + next.getId().toUnqualifiedVersionless().getValue() + " refers to unknown component " + nextRef + ", ignoring this parameter (valid values: " + existingParams + ")";
|
||||
ourLog.warn(message);
|
||||
myInterceptorBroadcaster.callHooks(Pointcut.PERFTRACE_MESSAGE, new PerformanceMessage().setMessage(message));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -182,6 +204,8 @@ public abstract class BaseSearchParamRegistry<SP extends IBaseResource> implemen
|
|||
}
|
||||
}
|
||||
|
||||
ourLog.trace("Have {} unique search params", activeParamNamesToUniqueSearchParams.size());
|
||||
|
||||
myActiveUniqueSearchParams = activeUniqueSearchParams;
|
||||
myActiveParamNamesToUniqueSearchParams = activeParamNamesToUniqueSearchParams;
|
||||
}
|
||||
|
@ -225,12 +249,15 @@ public abstract class BaseSearchParamRegistry<SP extends IBaseResource> implemen
|
|||
IBundleProvider allSearchParamsBp = mySearchParamProvider.search(params);
|
||||
int size = allSearchParamsBp.size();
|
||||
|
||||
ourLog.trace("Loaded {} search params from the DB", size);
|
||||
|
||||
// Just in case..
|
||||
if (size >= MAX_MANAGED_PARAM_COUNT) {
|
||||
ourLog.warn("Unable to support >" + MAX_MANAGED_PARAM_COUNT + " search params!");
|
||||
size = MAX_MANAGED_PARAM_COUNT;
|
||||
}
|
||||
|
||||
int overriddenCount = 0;
|
||||
List<IBaseResource> allSearchParams = allSearchParamsBp.getResources(0, size);
|
||||
for (IBaseResource nextResource : allSearchParams) {
|
||||
SP nextSp = (SP) nextResource;
|
||||
|
@ -252,11 +279,14 @@ public abstract class BaseSearchParamRegistry<SP extends IBaseResource> implemen
|
|||
String name = runtimeSp.getName();
|
||||
if (myModelConfig.isDefaultSearchParamsCanBeOverridden() || !searchParamMap.containsKey(name)) {
|
||||
searchParamMap.put(name, runtimeSp);
|
||||
overriddenCount++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ourLog.trace("Have overridden {} built-in search parameters", overriddenCount);
|
||||
|
||||
Map<String, Map<String, RuntimeSearchParam>> activeSearchParams = new HashMap<>();
|
||||
for (Map.Entry<String, Map<String, RuntimeSearchParam>> nextEntry : searchParams.entrySet()) {
|
||||
for (RuntimeSearchParam nextSp : nextEntry.getValue().values()) {
|
||||
|
@ -323,7 +353,7 @@ public abstract class BaseSearchParamRegistry<SP extends IBaseResource> implemen
|
|||
|
||||
int refreshCacheWithRetry() {
|
||||
Retrier<Integer> refreshCacheRetrier = new Retrier(() -> {
|
||||
synchronized(BaseSearchParamRegistry.this) {
|
||||
synchronized (BaseSearchParamRegistry.this) {
|
||||
return mySearchParamProvider.refreshCache(this, REFRESH_INTERVAL);
|
||||
}
|
||||
}, MAX_RETRIES);
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
package ca.uhn.fhir.jpa.subscription.module;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR Subscription Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 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.model.interceptor.api.HookParams;
|
||||
|
||||
|
|
|
@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.subscription.module.cache;
|
|||
* 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.
|
||||
|
|
|
@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.subscription.module.subscriber.websocket;
|
|||
* 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.
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
package ca.uhn.fhir.jpa.subscription.module.subscriber.websocket;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR Subscription Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 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.subscription.module.CanonicalSubscriptionChannelType;
|
||||
import ca.uhn.fhir.jpa.subscription.module.cache.ActiveSubscription;
|
||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionRegistry;
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
package ca.uhn.fhir.jpa.subscription.module.subscriber.websocket;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR Subscription Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 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.subscription.module.cache.ActiveSubscription;
|
||||
|
||||
public class WebsocketValidationResponse {
|
||||
|
|
|
@ -25,6 +25,7 @@ import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
|
|||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
||||
|
@ -98,18 +99,20 @@ abstract class BaseOutcomeReturningMethodBindingWithResourceParam extends BaseOu
|
|||
}
|
||||
if (myResourceParameterIndex != -1) {
|
||||
IBaseResource resource = ((IBaseResource) theParams[myResourceParameterIndex]);
|
||||
String resourceId = resource.getIdElement().getIdPart();
|
||||
String urlId = theRequest.getId() != null ? theRequest.getId().getIdPart() : null;
|
||||
if (getContext().getVersion().getVersion().isOlderThan(FhirVersionEnum.DSTU3) == false) {
|
||||
resource.setId(theRequest.getId());
|
||||
}
|
||||
if (resource != null) {
|
||||
String resourceId = resource.getIdElement().getIdPart();
|
||||
String urlId = theRequest.getId() != null ? theRequest.getId().getIdPart() : null;
|
||||
if (getContext().getVersion().getVersion().isOlderThan(FhirVersionEnum.DSTU3) == false) {
|
||||
resource.setId(theRequest.getId());
|
||||
}
|
||||
|
||||
String matchUrl = null;
|
||||
if (myConditionalUrlIndex != -1) {
|
||||
matchUrl = (String) theParams[myConditionalUrlIndex];
|
||||
matchUrl = defaultIfBlank(matchUrl, null);
|
||||
String matchUrl = null;
|
||||
if (myConditionalUrlIndex != -1) {
|
||||
matchUrl = (String) theParams[myConditionalUrlIndex];
|
||||
matchUrl = defaultIfBlank(matchUrl, null);
|
||||
}
|
||||
validateResourceIdAndUrlIdForNonConditionalOperation(resource, resourceId, urlId, matchUrl);
|
||||
}
|
||||
validateResourceIdAndUrlIdForNonConditionalOperation(resource, resourceId, urlId, matchUrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -139,8 +139,9 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
|||
return provideStructureDefinitionMap(theContext).get(theUrl);
|
||||
}
|
||||
|
||||
ValueSet fetchValueSet(FhirContext theContext, String theSystem) {
|
||||
return (ValueSet) fetchCodeSystemOrValueSet(theContext, theSystem, false);
|
||||
@Override
|
||||
public ValueSet fetchValueSet(FhirContext theContext, String uri) {
|
||||
return (ValueSet) fetchCodeSystemOrValueSet(theContext, uri, false);
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
|
|
|
@ -4,6 +4,7 @@ import java.util.List;
|
|||
|
||||
import org.hl7.fhir.dstu2016may.model.CodeSystem;
|
||||
import org.hl7.fhir.dstu2016may.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.dstu2016may.model.ValueSet;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.hl7.fhir.dstu2016may.model.StructureDefinition;
|
||||
import org.hl7.fhir.dstu2016may.model.ValueSet.ConceptSetComponent;
|
||||
|
@ -33,14 +34,23 @@ public interface IValidationSupport
|
|||
List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext);
|
||||
|
||||
/**
|
||||
* Fetch a code system by ID
|
||||
*
|
||||
* @param theSystem
|
||||
* The code system
|
||||
* Fetch a code system by Uri
|
||||
*
|
||||
* @param uri
|
||||
* Canonical Uri of the code system
|
||||
* @return The valueset (must not be null, but can be an empty ValueSet)
|
||||
*/
|
||||
@Override
|
||||
CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem);
|
||||
CodeSystem fetchCodeSystem(FhirContext theContext, String uri);
|
||||
|
||||
/**
|
||||
* Fetch a valueset by Uri
|
||||
*
|
||||
* @param uri
|
||||
* Canonical Uri of the ValueSet
|
||||
* @return The valueset (must not be null, but can be an empty ValueSet)
|
||||
*/
|
||||
ValueSet fetchValueSet(FhirContext theContext, String uri);
|
||||
|
||||
/**
|
||||
* Loads a resource needed by the validation (a StructureDefinition, or a
|
||||
|
|
|
@ -99,8 +99,13 @@ public class PrePopulatedValidationSupport implements IValidationSupport {
|
|||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem) {
|
||||
return myCodeSystems.get(theSystem);
|
||||
public CodeSystem fetchCodeSystem(FhirContext theContext, String uri) {
|
||||
return myCodeSystems.get(uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet fetchValueSet(FhirContext theContext, String uri) {
|
||||
return myValueSets.get(uri);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.hl7.fhir.dstu2016may.hapi.validation;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import org.hl7.fhir.dstu2016may.model.CodeSystem;
|
||||
import org.hl7.fhir.dstu2016may.model.StructureDefinition;
|
||||
import org.hl7.fhir.dstu2016may.model.ValueSet;
|
||||
import org.hl7.fhir.dstu2016may.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.dstu2016may.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
@ -78,9 +79,9 @@ public class ValidationSupportChain implements IValidationSupport {
|
|||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theCtx, String theSystem) {
|
||||
public CodeSystem fetchCodeSystem(FhirContext theCtx, String uri) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
CodeSystem retVal = next.fetchCodeSystem(theCtx, theSystem);
|
||||
CodeSystem retVal = next.fetchCodeSystem(theCtx, uri);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
|
@ -88,6 +89,18 @@ public class ValidationSupportChain implements IValidationSupport {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet fetchValueSet(FhirContext theCtx, String uri) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
ValueSet retVal = next.fetchValueSet(theCtx, uri);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
|
|
|
@ -155,8 +155,9 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
ValueSet fetchValueSet(FhirContext theContext, String theSystem) {
|
||||
return (ValueSet) fetchCodeSystemOrValueSet(theContext, theSystem, false);
|
||||
@Override
|
||||
public ValueSet fetchValueSet(FhirContext theContext, String uri) {
|
||||
return (ValueSet) fetchCodeSystemOrValueSet(theContext, uri, false);
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
|
|
|
@ -5,6 +5,7 @@ import java.util.List;
|
|||
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.dstu3.model.StructureDefinition;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
@ -32,15 +33,24 @@ public interface IValidationSupport
|
|||
@Override
|
||||
List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext);
|
||||
|
||||
/**
|
||||
* Fetch a code system by ID
|
||||
*
|
||||
* @param theSystem
|
||||
* The code system
|
||||
* @return The valueset (must not be null, but can be an empty ValueSet)
|
||||
*/
|
||||
@Override
|
||||
CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem);
|
||||
/**
|
||||
* Fetch a code system by Uri
|
||||
*
|
||||
* @param uri
|
||||
* Canonical Uri of the code system
|
||||
* @return The valueset (must not be null, but can be an empty ValueSet)
|
||||
*/
|
||||
@Override
|
||||
CodeSystem fetchCodeSystem(FhirContext theContext, String uri);
|
||||
|
||||
/**
|
||||
* Fetch a valueset by Uri
|
||||
*
|
||||
* @param uri
|
||||
* Canonical Uri of the ValueSet
|
||||
* @return The valueset (must not be null, but can be an empty ValueSet)
|
||||
*/
|
||||
ValueSet fetchValueSet(FhirContext theContext, String uri);
|
||||
|
||||
/**
|
||||
* Loads a resource needed by the validation (a StructureDefinition, or a
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.annotation.Create;
|
||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
|
@ -10,14 +13,17 @@ import ca.uhn.fhir.util.PortUtil;
|
|||
import ca.uhn.fhir.util.TestUtil;
|
||||
import com.google.common.base.Charsets;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.dstu3.model.OperationOutcome;
|
||||
import org.hl7.fhir.dstu3.model.OperationOutcome.IssueType;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
|
@ -26,6 +32,7 @@ import org.junit.AfterClass;
|
|||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -93,6 +100,22 @@ public class ServerExceptionDstu3Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostWithNoBody() throws IOException {
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
|
||||
try (CloseableHttpResponse status = ourClient.execute(httpPost)) {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(status.getStatusLine().toString());
|
||||
ourLog.info(responseContent);
|
||||
|
||||
assertEquals(201, status.getStatusLine().getStatusCode());
|
||||
assertThat(status.getFirstHeader("Location").getValue(), containsString("Patient/123"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAuthorize() throws Exception {
|
||||
|
||||
|
@ -125,6 +148,12 @@ public class ServerExceptionDstu3Test {
|
|||
throw ourException;
|
||||
}
|
||||
|
||||
@Create()
|
||||
public MethodOutcome create(@ResourceParam Patient thePatient) {
|
||||
Validate.isTrue(thePatient == null);
|
||||
return new MethodOutcome().setId(new IdType("Patient/123"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
|
|
|
@ -158,8 +158,9 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
|||
return provideStructureDefinitionMap(theContext).get(url);
|
||||
}
|
||||
|
||||
ValueSet fetchValueSet(FhirContext theContext, String theSystem) {
|
||||
return (ValueSet) fetchCodeSystemOrValueSet(theContext, theSystem, false);
|
||||
@Override
|
||||
public ValueSet fetchValueSet(FhirContext theContext, String uri) {
|
||||
return (ValueSet) fetchCodeSystemOrValueSet(theContext, uri, false);
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
|
|
|
@ -6,6 +6,7 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
|||
import org.hl7.fhir.r4.model.CodeSystem;
|
||||
import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r4.terminologies.ValueSetExpander;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
|
@ -32,14 +33,23 @@ public interface IValidationSupport
|
|||
List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext);
|
||||
|
||||
/**
|
||||
* Fetch a code system by ID
|
||||
* Fetch a code system by Uri
|
||||
*
|
||||
* @param theSystem
|
||||
* The code system
|
||||
* @return The valueset (must not be null, but can be an empty ValueSet)
|
||||
* @param uri
|
||||
* Canonical Uri of the code system
|
||||
* @return The valueset (must not be null, but can be an empty ValueSet)
|
||||
*/
|
||||
@Override
|
||||
CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem);
|
||||
CodeSystem fetchCodeSystem(FhirContext theContext, String uri);
|
||||
|
||||
/**
|
||||
* Fetch a valueset by Uri
|
||||
*
|
||||
* @param uri
|
||||
* Canonical Uri of the ValueSet
|
||||
* @return The valueset (must not be null, but can be an empty ValueSet)
|
||||
*/
|
||||
ValueSet fetchValueSet(FhirContext theContext, String uri);
|
||||
|
||||
/**
|
||||
* Loads a resource needed by the validation (a StructureDefinition, or a
|
||||
|
|
|
@ -41,8 +41,13 @@ public class CachingValidationSupport implements IValidationSupport {
|
|||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem) {
|
||||
return myWrap.fetchCodeSystem(theContext, theSystem);
|
||||
public CodeSystem fetchCodeSystem(FhirContext theContext, String uri) {
|
||||
return myWrap.fetchCodeSystem(theContext, uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet fetchValueSet(FhirContext theContext, String uri) {
|
||||
return myWrap.fetchValueSet(theContext, uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -146,11 +146,16 @@ public class PrePopulatedValidationSupport implements IValidationSupport {
|
|||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem) {
|
||||
return myCodeSystems.get(theSystem);
|
||||
}
|
||||
public CodeSystem fetchCodeSystem(FhirContext theContext, String uri) {
|
||||
return myCodeSystems.get(uri);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ValueSet fetchValueSet(FhirContext theContext, String uri) {
|
||||
return myValueSets.get(uri);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||
if (theClass.equals(StructureDefinition.class)) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
|||
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||
import org.hl7.fhir.dstu3.model.StructureDefinition;
|
||||
import org.hl7.fhir.dstu3.model.UriType;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
@ -101,6 +102,17 @@ public class ValidationSupportChain implements IValidationSupport {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet fetchValueSet(FhirContext theCtx, String uri) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
ValueSet retVal = next.fetchValueSet(theCtx, uri);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
|
|
|
@ -42,8 +42,13 @@ public class CachingValidationSupport implements IValidationSupport {
|
|||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem) {
|
||||
return myWrap.fetchCodeSystem(theContext, theSystem);
|
||||
public CodeSystem fetchCodeSystem(FhirContext theContext, String uri) {
|
||||
return myWrap.fetchCodeSystem(theContext, uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet fetchValueSet(FhirContext theContext, String uri) {
|
||||
return myWrap.fetchValueSet(theContext, uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -146,12 +146,18 @@ public class PrePopulatedValidationSupport implements IValidationSupport {
|
|||
return new ArrayList<StructureDefinition>(myStructureDefinitions.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem) {
|
||||
return myCodeSystems.get(theSystem);
|
||||
}
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theContext, String uri) {
|
||||
return myCodeSystems.get(uri);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ValueSet fetchValueSet(FhirContext theContext, String uri) {
|
||||
return myValueSets.get(uri);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||
if (theClass.equals(StructureDefinition.class)) {
|
||||
|
|
|
@ -7,6 +7,7 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
|||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r4.model.CodeSystem;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r4.terminologies.ValueSetExpander;
|
||||
|
||||
|
@ -70,9 +71,20 @@ public class ValidationSupportChain implements IValidationSupport {
|
|||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theCtx, String theSystem) {
|
||||
public CodeSystem fetchCodeSystem(FhirContext theCtx, String uri) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
CodeSystem retVal = next.fetchCodeSystem(theCtx, theSystem);
|
||||
CodeSystem retVal = next.fetchCodeSystem(theCtx, uri);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet fetchValueSet(FhirContext theCtx, String uri) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
ValueSet retVal = next.fetchValueSet(theCtx, uri);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
|
|
5
pom.xml
5
pom.xml
|
@ -1464,7 +1464,7 @@
|
|||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>2.21.0</version>
|
||||
<version>3.0.0-M3</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
|
@ -1491,7 +1491,7 @@
|
|||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.21.0</version>
|
||||
<version>3.0.0-M3</version>
|
||||
<configuration>
|
||||
<redirectTestOutputToFile>true</redirectTestOutputToFile>
|
||||
<runOrder>random</runOrder>
|
||||
|
@ -2268,7 +2268,6 @@
|
|||
<module>hapi-fhir-jpaserver-elasticsearch</module>
|
||||
<module>hapi-fhir-jpaserver-migrate</module>
|
||||
<module>restful-server-example</module>
|
||||
<module>restful-server-example-test</module>
|
||||
<module>hapi-fhir-testpage-overlay</module>
|
||||
<module>hapi-fhir-jpaserver-uhnfhirtest</module>
|
||||
<module>hapi-fhir-client-okhttp</module>
|
||||
|
|
|
@ -1,125 +0,0 @@
|
|||
/target/
|
||||
|
||||
# Created by https://www.gitignore.io
|
||||
|
||||
### Java ###
|
||||
*.class
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.ear
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
|
||||
### Maven ###
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
|
||||
|
||||
### Vim ###
|
||||
[._]*.s[a-w][a-z]
|
||||
[._]s[a-w][a-z]
|
||||
*.un~
|
||||
Session.vim
|
||||
.netrwhist
|
||||
*~
|
||||
|
||||
|
||||
### Intellij ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
|
||||
|
||||
*.iml
|
||||
|
||||
## Directory-based project format:
|
||||
.idea/
|
||||
# if you remove the above rule, at least ignore the following:
|
||||
|
||||
# User-specific stuff:
|
||||
# .idea/workspace.xml
|
||||
# .idea/tasks.xml
|
||||
# .idea/dictionaries
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
# .idea/dataSources.ids
|
||||
# .idea/dataSources.xml
|
||||
# .idea/sqlDataSources.xml
|
||||
# .idea/dynamic.xml
|
||||
# .idea/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
# .idea/gradle.xml
|
||||
# .idea/libraries
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
# .idea/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
|
||||
|
||||
|
||||
### Eclipse ###
|
||||
*.pydevproject
|
||||
.metadata
|
||||
.gradle
|
||||
bin/
|
||||
tmp/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
local.properties
|
||||
.loadpath
|
||||
|
||||
# Eclipse Core
|
||||
.project
|
||||
|
||||
# External tool builders
|
||||
.externalToolBuilders/
|
||||
|
||||
# Locally stored "Eclipse launch configurations"
|
||||
*.launch
|
||||
|
||||
# CDT-specific
|
||||
.cproject
|
||||
|
||||
# JDT-specific (Eclipse Java Development Tools)
|
||||
|
||||
# PDT-specific
|
||||
.buildpath
|
||||
|
||||
# sbteclipse plugin
|
||||
.target
|
||||
|
||||
# TeXlipse plugin
|
||||
.texlipse
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.8.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>restful-server-example-test</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>HAPI FHIR Sample RESTful Server - Tests</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-base</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu2</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlets</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -1,97 +0,0 @@
|
|||
package ca.uhn.example;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.hamcrest.core.StringContains;
|
||||
import org.junit.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
|
||||
public class ExampleTest {
|
||||
|
||||
private static Integer ourPort;
|
||||
private static Server ourServer;
|
||||
private static FhirContext ourCtx;
|
||||
private static IGenericClient ourClient;
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
if (ourServer != null) {
|
||||
ourServer.stop();
|
||||
}
|
||||
|
||||
System.clearProperty("ca.uhn.fhir.to.TesterConfig_SYSPROP_FORCE_SERVERS");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests here have some weird windows inconsistency relating to the path for finding the WAR file. Since this test isn't really important to work multiplatform, we can skip it
|
||||
*/
|
||||
public static boolean isWindows() {
|
||||
return System.getProperty("os.name").startsWith("Windows");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test01Search() throws Exception {
|
||||
if (isWindows()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Bundle results = ourClient.search().forResource(Patient.class).returnBundle(Bundle.class).execute();
|
||||
assertEquals(1, results.getEntry().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test02Read() throws Exception {
|
||||
if (isWindows()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Patient results = ourClient.read(Patient.class, "1");
|
||||
assertThat(results.getNameFirstRep().getGivenAsSingleString(), StringContains.containsString("PatientOne"));
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
if (isWindows()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ourPort != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ourPort = RandomServerPortProvider.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
String base = "http://localhost:" + ourPort + "/fhir";
|
||||
System.setProperty("ca.uhn.fhir.to.TesterConfig_SYSPROP_FORCE_SERVERS", "example , Restful Server Example , " + base);
|
||||
|
||||
WebAppContext root = new WebAppContext();
|
||||
root.setAllowDuplicateFragmentNames(true);
|
||||
|
||||
root.setWar(new File("../restful-server-example/target/restful-server-example.war").toURI().toString());
|
||||
root.setContextPath("/");
|
||||
root.setAttribute(WebAppContext.BASETEMPDIR, "target/tempextrtact");
|
||||
root.setParentLoaderPriority(false);
|
||||
root.setCopyWebInf(true);
|
||||
root.setCopyWebDir(true);
|
||||
|
||||
ourServer.setHandler(root);
|
||||
|
||||
ourServer.start();
|
||||
|
||||
ourCtx = FhirContext.forDstu2();
|
||||
ourClient = ourCtx.newRestfulGenericClient(base);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package ca.uhn.example;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Finds and provides a free port to use in unit tests
|
||||
*/
|
||||
public class RandomServerPortProvider {
|
||||
|
||||
private static List<Integer> ourPorts = new ArrayList<Integer>();
|
||||
|
||||
public static int findFreePort() {
|
||||
ServerSocket server;
|
||||
try {
|
||||
server = new ServerSocket(0);
|
||||
int port = server.getLocalPort();
|
||||
ourPorts.add(port);
|
||||
server.close();
|
||||
Thread.sleep(500);
|
||||
return port;
|
||||
} catch (IOException e) {
|
||||
throw new Error(e);
|
||||
} catch (InterruptedException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Integer> list() {
|
||||
return ourPorts;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
<configuration>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%file:%line] - %msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="org.eclipse" additivity="false" level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
<logger name="org.apache" additivity="false" level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
<logger name="org.thymeleaf" additivity="false" level="warn">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
|
||||
<!--
|
||||
<logger name="ca.uhn.fhir.rest.client" additivity="false" level="trace">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
-->
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
|
@ -36,4 +36,4 @@
|
|||
<url-pattern>/fhir/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
</web-app>
|
||||
</web-app>
|
||||
|
|
|
@ -137,6 +137,15 @@
|
|||
the resource version is not updated and no new version is created. In this situation,
|
||||
the update time was modified however. It will no longer be updated.
|
||||
</action>
|
||||
<action type="fix">
|
||||
Performing a PUT or POST against a HAPI FHIR Server with no request body caused an
|
||||
HTTP 500 to be returned instead of a more appropriate HTTP 400. This has been
|
||||
corrected.
|
||||
</action>
|
||||
<action type="fix" issue="1255">
|
||||
The fetchValueSet method on IValidationSupport implementation was not visible and could
|
||||
not be overridden. Thanks to Patrick Werner for the pull reuqest!
|
||||
</action>
|
||||
</release>
|
||||
<release version="3.7.0" date="2019-02-06" description="Gale">
|
||||
<action type="add">
|
||||
|
|
Loading…
Reference in New Issue