Merge remote-tracking branch 'remotes/origin/master' into ks-flyway

# Conflicts:
#	hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/DropIndexTask.java
#	hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/DropTableTask.java
This commit is contained in:
Ken Stevens 2019-11-01 13:37:00 -04:00
commit bee993a0ec
16 changed files with 702 additions and 219 deletions

View File

@ -46,6 +46,7 @@ import ca.uhn.fhir.rest.api.server.IRestfulResponse;
import ca.uhn.fhir.rest.server.*;
import ca.uhn.fhir.rest.server.method.BaseMethodBinding;
import ca.uhn.fhir.util.ReflectionUtil;
import java.util.stream.Collectors;
/**
* This is the conformance provider for the jax rs servers. It requires all providers to be registered during startup because the conformance profile is generated during the postconstruct phase.
@ -119,7 +120,8 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
return;
}
for (Entry<Class<? extends IResourceProvider>, IResourceProvider> provider : getProviders().entrySet()) {
ConcurrentHashMap<Class<? extends IResourceProvider>, IResourceProvider> providers = getProviders();
for (Entry<Class<? extends IResourceProvider>, IResourceProvider> provider : providers.entrySet()) {
addProvider(provider.getValue(), provider.getKey());
}
List<BaseMethodBinding<?>> serverBindings = new ArrayList<BaseMethodBinding<?>>();
@ -128,6 +130,7 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
}
serverConfiguration.setServerBindings(serverBindings);
serverConfiguration.setResourceBindings(new LinkedList<ResourceBinding>(myResourceNameToBinding.values()));
serverConfiguration.computeSharedSupertypeForResourcePerName(providers.values());
HardcodedServerAddressStrategy hardcodedServerAddressStrategy = new HardcodedServerAddressStrategy();
hardcodedServerAddressStrategy.setValue(getBaseForServer());
serverConfiguration.setServerAddressStrategy(hardcodedServerAddressStrategy);

View File

@ -1,7 +1,6 @@
package ca.uhn.fhir.jaxrs.server;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsDummyPatientProvider;
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsMockPatientRestProviderDstu3;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.IResourceProvider;
@ -20,6 +19,8 @@ import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsDummyPatientProviderDstu3;
public class AbstractJaxRsConformanceProviderDstu3Test {
private static final String BASEURI = "http://basiuri";
@ -46,7 +47,7 @@ public class AbstractJaxRsConformanceProviderDstu3Test {
@Test
public void testConformance() throws Exception {
providers.put(AbstractJaxRsConformanceProvider.class, provider);
providers.put(TestJaxRsDummyPatientProvider.class, new TestJaxRsDummyPatientProvider());
providers.put(TestJaxRsDummyPatientProviderDstu3.class, new TestJaxRsDummyPatientProviderDstu3());
Response response = createConformanceProvider(providers).conformance();
System.out.println(response);
}
@ -54,7 +55,7 @@ public class AbstractJaxRsConformanceProviderDstu3Test {
@Test
public void testConformanceUsingOptions() throws Exception {
providers.put(AbstractJaxRsConformanceProvider.class, provider);
providers.put(TestJaxRsDummyPatientProvider.class, new TestJaxRsDummyPatientProvider());
providers.put(TestJaxRsDummyPatientProviderDstu3.class, new TestJaxRsDummyPatientProviderDstu3());
Response response = createConformanceProvider(providers).conformanceUsingOptions();
System.out.println(response);
}

View File

@ -23,14 +23,14 @@ package ca.uhn.fhir.jpa.migrate.taskdef;
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
import ca.uhn.fhir.jpa.migrate.JdbcUtils;
import org.apache.commons.lang3.Validate;
import org.intellij.lang.annotations.Language;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.Optional;
import java.util.Set;
import java.util.*;
public class DropIndexTask extends BaseTableTask<DropIndexTask> {
@ -63,10 +63,12 @@ public class DropIndexTask extends BaseTableTask<DropIndexTask> {
boolean isUnique = JdbcUtils.isIndexUnique(getConnectionProperties(), getTableName(), myIndexName);
String uniquenessString = isUnique ? "unique" : "non-unique";
Optional<String> sql = createDropIndexSql(getConnectionProperties(), getTableName(), myIndexName, getDriverType());
if (sql.isPresent()) {
logInfo(ourLog, "Dropping {} index {} on table {}", uniquenessString, myIndexName, getTableName());
executeSql(getTableName(), sql.get());
List<String> sqls = createDropIndexSql(getConnectionProperties(), getTableName(), myIndexName, getDriverType());
if (!sqls.isEmpty()) {
logInfo("Dropping {} index {} on table {}", uniquenessString, myIndexName, getTableName());
}
for (@Language("SQL") String sql : sqls) {
executeSql(getTableName(), sql);
}
}
@ -75,35 +77,36 @@ public class DropIndexTask extends BaseTableTask<DropIndexTask> {
return this;
}
static Optional<String> createDropIndexSql(DriverTypeEnum.ConnectionProperties theConnectionProperties, String theTableName, String theIndexName, DriverTypeEnum theDriverType) throws SQLException {
static List<String> createDropIndexSql(DriverTypeEnum.ConnectionProperties theConnectionProperties, String theTableName, String theIndexName, DriverTypeEnum theDriverType) throws SQLException {
Validate.notBlank(theIndexName, "theIndexName must not be blank");
Validate.notBlank(theTableName, "theTableName must not be blank");
if (!JdbcUtils.getIndexNames(theConnectionProperties, theTableName).contains(theIndexName)) {
return Optional.empty();
return Collections.emptyList();
}
boolean isUnique = JdbcUtils.isIndexUnique(theConnectionProperties, theTableName, theIndexName);
String sql = null;
List<String> sql = new ArrayList<>();
if (isUnique) {
// Drop constraint
switch (theDriverType) {
case MYSQL_5_7:
case MARIADB_10_1:
sql = "alter table " + theTableName + " drop index " + theIndexName;
sql.add("alter table " + theTableName + " drop index " + theIndexName);
break;
case H2_EMBEDDED:
case DERBY_EMBEDDED:
sql = "drop index " + theIndexName;
sql.add("drop index " + theIndexName);
break;
case POSTGRES_9_4:
sql = "drop index " + theIndexName + " cascade";
sql.add("alter table " + theTableName + " drop constraint if exists " + theIndexName + " cascade");
sql.add("drop index if exists " + theIndexName + " cascade");
break;
case ORACLE_12C:
case MSSQL_2012:
sql = "alter table " + theTableName + " drop constraint " + theIndexName;
sql.add("alter table " + theTableName + " drop constraint " + theIndexName);
break;
}
} else {
@ -111,20 +114,20 @@ public class DropIndexTask extends BaseTableTask<DropIndexTask> {
switch (theDriverType) {
case MYSQL_5_7:
case MARIADB_10_1:
sql = "alter table " + theTableName + " drop index " + theIndexName;
sql.add("alter table " + theTableName + " drop index " + theIndexName);
break;
case POSTGRES_9_4:
case DERBY_EMBEDDED:
case H2_EMBEDDED:
case ORACLE_12C:
sql = "drop index " + theIndexName;
sql.add("drop index " + theIndexName);
break;
case MSSQL_2012:
sql = "drop index " + theTableName + "." + theIndexName;
sql.add("drop index " + theTableName + "." + theIndexName);
break;
}
}
return Optional.of(sql);
return sql;
}
@Override

View File

@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.migrate.taskdef;
*/
import ca.uhn.fhir.jpa.migrate.JdbcUtils;
import org.intellij.lang.annotations.Language;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -52,21 +53,24 @@ public class DropTableTask extends BaseTableTask<DropTableTask> {
for (String next : foreignKeys) {
List<String> sql = DropForeignKeyTask.generateSql(getTableName(), next, getDriverType());
for (String nextSql : sql) {
for (@Language("SQL") String nextSql : sql) {
executeSql(getTableName(), nextSql);
}
}
for (String nextIndex : indexNames) {
Optional<String> sql = DropIndexTask.createDropIndexSql(getConnectionProperties(), getTableName(), nextIndex, getDriverType());
if (sql.isPresent()) {
logInfo(ourLog, "Dropping index {} on table {} in preparation for table delete", nextIndex, getTableName());
executeSql(getTableName(), sql.get());
List<String> sqls = DropIndexTask.createDropIndexSql(getConnectionProperties(), getTableName(), nextIndex, getDriverType());
if (!sqls.isEmpty()) {
logInfo("Dropping index {} on table {} in preparation for table delete", nextIndex, getTableName());
}
for (@Language("SQL") String sql : sqls) {
executeSql(getTableName(), sql);
}
}
logInfo(ourLog, "Dropping table: {}", getTableName());
@Language("SQL")
String sql = "DROP TABLE " + getTableName();
executeSql(getTableName(), sql);

View File

@ -0,0 +1,65 @@
package ca.uhn.fhir.rest.server;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import org.hl7.fhir.instance.model.api.IBaseResource;
/**
* <pre>
* When populating the StructureDefinition links in a capability statement,
* it can be useful to know the lowest common superclass for the profiles in use for a given resource name.
* This class finds this superclass, by incrementally computing the greatest common sequence of ancestor classes in the class hierarchies of registered resources.
* For instance, given the following classes
* MyPatient extends Patient
* MyPatient2 extends MyPatient
* MyPatient3 extends MyPatient
* MyPatient4 extends MyPatient3
* this class will find the common ancestor sequence "IBaseResource -> Patient -> MyPatient". MyPatient is the lowest common superclass in this hierarchy.
* </pre>
*
*/
public class CommonResourceSupertypeScanner {
private List<Class<? extends IBaseResource>> greatestSharedAncestorsDescending;
private boolean initialized;
/**
* Recomputes the lowest common superclass by adding a new resource definition to the hierarchy.
* @param resourceClass The resource class to add.
*/
public void register(Class<? extends IBaseResource> resourceClass) {
List<Class<? extends IBaseResource>> resourceClassesInHierarchy = new LinkedList<>();
Class<?> currentClass = resourceClass;
while (IBaseResource.class.isAssignableFrom(currentClass)
&& currentClass.getAnnotation(ResourceDef.class) != null) {
resourceClassesInHierarchy.add((Class<? extends IBaseResource>)currentClass);
currentClass = currentClass.getSuperclass();
}
Collections.reverse(resourceClassesInHierarchy);
if (initialized) {
for (int i = 0; i < Math.min(resourceClassesInHierarchy.size(), greatestSharedAncestorsDescending.size()); i++) {
if (greatestSharedAncestorsDescending.get(i) != resourceClassesInHierarchy.get(i)) {
greatestSharedAncestorsDescending = greatestSharedAncestorsDescending.subList(0, i);
break;
}
}
} else {
greatestSharedAncestorsDescending = resourceClassesInHierarchy;
initialized = true;
}
}
/**
* @return The lowest common superclass of currently registered resources.
*/
public Optional<Class<? extends IBaseResource>> getLowestCommonSuperclass() {
if (!initialized || greatestSharedAncestorsDescending.isEmpty()) {
return Optional.empty();
}
return Optional.ofNullable(greatestSharedAncestorsDescending.get(greatestSharedAncestorsDescending.size() - 1));
}
}

View File

@ -208,6 +208,7 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
} catch (Exception e) {
// fall through
}
result.computeSharedSupertypeForResourcePerName(getResourceProviders());
return result;
}
@ -923,8 +924,8 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
preProcessedParams.add(HttpServletRequest.class, theRequest);
preProcessedParams.add(HttpServletResponse.class, theResponse);
if (!myInterceptorService.callHooks(Pointcut.SERVER_INCOMING_REQUEST_PRE_PROCESSED, preProcessedParams)) {
return;
}
return;
}
String requestPath = getRequestPath(requestFullPath, servletContextPath, servletPath);
@ -976,8 +977,8 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
postProcessedParams.add(HttpServletRequest.class, theRequest);
postProcessedParams.add(HttpServletResponse.class, theResponse);
if (!myInterceptorService.callHooks(Pointcut.SERVER_INCOMING_REQUEST_POST_PROCESSED, postProcessedParams)) {
return;
}
return;
}
/*
* Actually invoke the server method. This call is to a HAPI method binding, which
@ -996,7 +997,7 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
myInterceptorService.callHooks(Pointcut.SERVER_PROCESSING_COMPLETED_NORMALLY, hookParams);
ourLog.trace("Done writing to stream: {}", outputStreamOrWriter);
}
}
} catch (NotModifiedException | AuthenticationException e) {
@ -1007,8 +1008,8 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
handleExceptionParams.add(HttpServletResponse.class, theResponse);
handleExceptionParams.add(BaseServerResponseException.class, e);
if (!myInterceptorService.callHooks(Pointcut.SERVER_HANDLE_EXCEPTION, handleExceptionParams)) {
return;
}
return;
}
writeExceptionToResponse(theResponse, e);
@ -1063,8 +1064,8 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
handleExceptionParams.add(HttpServletResponse.class, theResponse);
handleExceptionParams.add(BaseServerResponseException.class, exception);
if (!myInterceptorService.callHooks(Pointcut.SERVER_HANDLE_EXCEPTION, handleExceptionParams)) {
return;
}
return;
}
/*
* If we're handling an exception, no summary mode should be applied

View File

@ -33,11 +33,16 @@ import java.util.*;
import static org.apache.commons.lang3.StringUtils.isBlank;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import java.util.stream.Collectors;
import org.hl7.fhir.instance.model.api.IBaseResource;
public class RestfulServerConfiguration {
private static final Logger ourLog = LoggerFactory.getLogger(RestfulServerConfiguration.class);
private Collection<ResourceBinding> resourceBindings;
private List<BaseMethodBinding<?>> serverBindings;
private Map<String, Class<? extends IBaseResource>> resourceNameToSharedSupertype;
private String implementationDescription;
private String serverVersion = VersionUtil.getVersion();
private String serverName = "HAPI FHIR";
@ -88,6 +93,15 @@ public class RestfulServerConfiguration {
return this;
}
public Map<String, Class<? extends IBaseResource>> getNameToSharedSupertype() {
return resourceNameToSharedSupertype;
}
public RestfulServerConfiguration setNameToSharedSupertype(Map<String, Class<? extends IBaseResource>> resourceNameToSharedSupertype) {
this.resourceNameToSharedSupertype = resourceNameToSharedSupertype;
return this;
}
/**
* Get the implementationDescription
*
@ -268,6 +282,34 @@ public class RestfulServerConfiguration {
return resourceToMethods;
}
/*
* Populates {@link #resourceNameToSharedSupertype} by scanning the given resource providers. Only resource provider getResourceType values
* are taken into account. {@link ProvidesResources} and method return types are deliberately ignored.
*
* Given a resource name, the common superclass for all getResourceType return values for that name's providers is the common superclass
* for all returned/received resources with that name. Since {@link ProvidesResources} resources and method return types must also be
* subclasses of this common supertype, they can't affect the result of this method.
*/
public void computeSharedSupertypeForResourcePerName(Collection<IResourceProvider> providers) {
Map<String, CommonResourceSupertypeScanner> resourceNameToScanner = new HashMap<>();
List<Class<? extends IBaseResource>> providedResourceClasses = providers.stream()
.map(provider -> provider.getResourceType())
.collect(Collectors.toList());
providedResourceClasses.stream()
.forEach(resourceClass -> {
RuntimeResourceDefinition baseDefinition = getFhirContext().getResourceDefinition(resourceClass).getBaseDefinition();
CommonResourceSupertypeScanner scanner = resourceNameToScanner.computeIfAbsent(baseDefinition.getName(), key -> new CommonResourceSupertypeScanner());
scanner.register(resourceClass);
});
resourceNameToSharedSupertype = resourceNameToScanner.entrySet().stream()
.filter(entry -> entry.getValue().getLowestCommonSuperclass().isPresent())
.collect(Collectors.toMap(
entry -> entry.getKey(),
entry -> entry.getValue().getLowestCommonSuperclass().get()));
}
private String createOperationName(OperationMethodBinding theMethodBinding) {
StringBuilder retVal = new StringBuilder();
if (theMethodBinding.getResourceName() != null) {

View File

@ -0,0 +1,132 @@
package ca.uhn.fhir.rest.server;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import java.util.List;
import static org.hamcrest.CoreMatchers.is;
import org.hl7.fhir.instance.model.api.IBaseMetaType;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import static org.junit.Assert.assertThat;
import org.junit.Test;
public class CommonResourceSupertypeScannerTest {
private final CommonResourceSupertypeScanner scanner = new CommonResourceSupertypeScanner();
@Test
public void testBaseClass() {
scanner.register(DemoPatient.class);
assertThat(scanner.getLowestCommonSuperclass().get(), is(DemoPatient.class));
}
@Test
public void testSubtype() {
scanner.register(DemoPatient.class);
scanner.register(DemoPatientTripleSub.class);
assertThat(scanner.getLowestCommonSuperclass().get(), is(DemoPatient.class));
}
@Test
public void testHierarchyBranch() {
scanner.register(DemoPatientSub.class);
scanner.register(DemoPatientSubSub.class);
scanner.register(DemoPatientSubSubTwo.class);
scanner.register(DemoPatientTripleSub.class);
assertThat(scanner.getLowestCommonSuperclass().get(), is(DemoPatientSub.class));
}
@Test
public void testSupertypeNotRegistered() {
scanner.register(DemoPatientTripleSub.class);
scanner.register(DemoPatientSubSubTwo.class);
assertThat(scanner.getLowestCommonSuperclass().get(), is(DemoPatientSub.class));
}
@Test
public void testOnlySubtype() {
scanner.register(DemoPatientTripleSub.class);
assertThat(scanner.getLowestCommonSuperclass().get(), is(DemoPatientTripleSub.class));
}
@Test
public void testEmpty() {
assertThat(scanner.getLowestCommonSuperclass().isPresent(), is(false));
}
@ResourceDef(name = "Patient")
private static class DemoPatient implements IBaseResource {
@Override
public IBaseMetaType getMeta() {
return null;
}
@Override
public IIdType getIdElement() {
return null;
}
@Override
public IBaseResource setId(String theId) {
return null;
}
@Override
public IBaseResource setId(IIdType theId) {
return null;
}
@Override
public FhirVersionEnum getStructureFhirVersionEnum() {
return null;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean hasFormatComment() {
return false;
}
@Override
public List<String> getFormatCommentsPre() {
return null;
}
@Override
public List<String> getFormatCommentsPost() {
return null;
}
@Override
public Object getUserData(String theName) {
return null;
}
@Override
public void setUserData(String theName, Object theValue) {
}
}
@ResourceDef(id = "subOne")
private static class DemoPatientSub extends DemoPatient {}
@ResourceDef(id = "subSubOne")
private static class DemoPatientSubSub extends DemoPatientSub {}
@ResourceDef(id = "subSubTwo")
private static class DemoPatientSubSubTwo extends DemoPatientSub {}
@ResourceDef(id = "tripleSub")
private static class DemoPatientTripleSub extends DemoPatientSubSub {}
}

View File

@ -34,6 +34,8 @@ import java.util.Map.Entry;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import ca.uhn.fhir.context.FhirContext;
/*
* #%L
* HAPI FHIR Structures - DSTU2 (FHIR v1.0.0)
@ -113,12 +115,12 @@ public class ServerCapabilityStatementProvider extends BaseServerCapabilityState
}
private Map<String, List<BaseMethodBinding<?>>> collectMethodBindings(RequestDetails theRequestDetails) {
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = new TreeMap<String, List<BaseMethodBinding<?>>>();
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = new TreeMap<>();
for (ResourceBinding next : getServerConfiguration(theRequestDetails).getResourceBindings()) {
String resourceName = next.getResourceName();
for (BaseMethodBinding<?> nextMethodBinding : next.getMethodBindings()) {
if (resourceToMethods.containsKey(resourceName) == false) {
resourceToMethods.put(resourceName, new ArrayList<BaseMethodBinding<?>>());
resourceToMethods.put(resourceName, new ArrayList<>());
}
resourceToMethods.get(resourceName).add(nextMethodBinding);
}
@ -231,13 +233,21 @@ public class ServerCapabilityStatementProvider extends BaseServerCapabilityState
Set<String> operationNames = new HashSet<>();
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = collectMethodBindings(theRequestDetails);
Map<String, Class<? extends IBaseResource>> resourceNameToSharedSupertype = serverConfiguration.getNameToSharedSupertype();
for (Entry<String, List<BaseMethodBinding<?>>> nextEntry : resourceToMethods.entrySet()) {
if (nextEntry.getKey().isEmpty() == false) {
Set<TypeRestfulInteraction> resourceOps = new HashSet<>();
CapabilityStatementRestResourceComponent resource = rest.addResource();
String resourceName = nextEntry.getKey();
RuntimeResourceDefinition def = serverConfiguration.getFhirContext().getResourceDefinition(resourceName);
RuntimeResourceDefinition def;
FhirContext context = serverConfiguration.getFhirContext();
if (resourceNameToSharedSupertype.containsKey(resourceName)) {
def = context.getResourceDefinition(resourceNameToSharedSupertype.get(resourceName));
} else {
def = context.getResourceDefinition(resourceName);
}
resource.getTypeElement().setValue(def.getName());
resource.getProfile().setReference((def.getResourceProfile(serverBase)));

View File

@ -3,6 +3,7 @@ package org.hl7.fhir.dstu3.hapi.rest.server;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.rest.annotation.*;
import ca.uhn.fhir.rest.api.MethodOutcome;
@ -91,7 +92,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new SearchProviderWithExplicitChains());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -131,7 +132,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new ConditionalProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -154,7 +155,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new ProviderWithExtendedOperationReturningBundle());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -181,7 +182,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new ProviderWithExtendedOperationReturningBundle());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs) {
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider() {
};
rs.setServerConformanceProvider(sc);
@ -203,7 +204,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new InstanceHistoryProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -222,7 +223,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new MultiOptionalProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -255,7 +256,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new NonConditionalProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -280,7 +281,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new MultiTypePatientProvider(), new MultiTypeEncounterProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -348,7 +349,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new SearchProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -367,7 +368,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new PlainProviderWithExtendedOperationOnNoType());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs) {
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider() {
@Override
public CapabilityStatement getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
return super.getServerConformance(theRequest, createRequestDetails(rs));
@ -407,7 +408,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new ProviderWithRequiredAndOptional());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -437,7 +438,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new VreadProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -457,7 +458,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new ReadProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -477,7 +478,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new SearchProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -517,7 +518,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new PatientResourceProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -550,7 +551,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new SearchProviderWithWhitelist());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -583,7 +584,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
@Test
public void testSearchReferenceParameterWithList() throws Exception {
RestfulServer rsNoType = new RestfulServer(ourCtx) {
RestfulServer rsNoType = new RestfulServer(ourCtx){
@Override
public RestfulServerConfiguration createConfiguration() {
RestfulServerConfiguration retVal = super.createConfiguration();
@ -592,7 +593,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
}
};
rsNoType.registerProvider(new SearchProviderWithListNoType());
ServerCapabilityStatementProvider scNoType = new ServerCapabilityStatementProvider(rsNoType);
ServerCapabilityStatementProvider scNoType = new ServerCapabilityStatementProvider();
rsNoType.setServerConformanceProvider(scNoType);
rsNoType.init(createServletConfig());
@ -600,7 +601,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
String confNoType = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(confNoType);
RestfulServer rsWithType = new RestfulServer(ourCtx) {
RestfulServer rsWithType = new RestfulServer(ourCtx){
@Override
public RestfulServerConfiguration createConfiguration() {
RestfulServerConfiguration retVal = super.createConfiguration();
@ -609,7 +610,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
}
};
rsWithType.registerProvider(new SearchProviderWithListWithType());
ServerCapabilityStatementProvider scWithType = new ServerCapabilityStatementProvider(rsWithType);
ServerCapabilityStatementProvider scWithType = new ServerCapabilityStatementProvider();
rsWithType.setServerConformanceProvider(scWithType);
rsWithType.init(createServletConfig());
@ -627,7 +628,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new SystemHistoryProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -646,7 +647,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new TypeHistoryProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -665,7 +666,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new MultiOptionalProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -682,7 +683,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new NamedQueryPlainProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -726,7 +727,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new NamedQueryResourceProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -759,8 +760,8 @@ public class ServerCapabilityStatementProviderDstu3Test {
assertThat(param.getUse(), is(OperationParameterUse.IN));
CapabilityStatementRestResourceComponent patientResource = restComponent.getResource().stream()
.filter(r -> patientResourceName.equals(r.getType()))
.findAny().get();
.filter(r -> patientResourceName.equals(r.getType()))
.findAny().get();
assertThat("Named query parameters should not appear in the resource search params", patientResource.getSearchParam(), is(empty()));
}
@ -769,7 +770,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new TypeLevelOperationProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -791,6 +792,26 @@ public class ServerCapabilityStatementProviderDstu3Test {
assertThat(opDef.getInstance(), is(false));
}
@Test
public void testProfiledResourceStructureDefinitionLinks() throws Exception {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setResourceProviders(new ProfiledPatientProvider(), new MultipleProfilesPatientProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance));
List<CapabilityStatementRestResourceComponent> resources = conformance.getRestFirstRep().getResource();
CapabilityStatementRestResourceComponent patientResource = resources.stream()
.filter(resource -> "Patient".equals(resource.getType()))
.findFirst().get();
assertThat(patientResource.getProfile().getReference(), containsString(PATIENT_SUB));
}
private List<String> toOperationIdParts(List<CapabilityStatementRestOperationComponent> theOperation) {
ArrayList<String> retVal = Lists.newArrayList();
for (CapabilityStatementRestOperationComponent next : theOperation) {
@ -883,7 +904,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
@Search(type = Patient.class)
public Patient findPatient(@Description(shortDefinition = "The patient's identifier") @OptionalParam(name = Patient.SP_IDENTIFIER) TokenParam theIdentifier,
@Description(shortDefinition = "The patient's name") @OptionalParam(name = Patient.SP_NAME) StringParam theName) {
@Description(shortDefinition = "The patient's name") @OptionalParam(name = Patient.SP_NAME) StringParam theName) {
return null;
}
@ -894,7 +915,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
@Operation(name = "someOp")
public IBundleProvider everything(javax.servlet.http.HttpServletRequest theServletRequest, @IdParam IdType theId,
@OperationParam(name = "someOpParam1") DateType theStart, @OperationParam(name = "someOpParam2") Encounter theEnd) {
@OperationParam(name = "someOpParam1") DateType theStart, @OperationParam(name = "someOpParam2") Encounter theEnd) {
return null;
}
@ -915,7 +936,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
@Operation(name = "someOp")
public IBundleProvider everything(javax.servlet.http.HttpServletRequest theServletRequest, @IdParam IdType theId,
@OperationParam(name = "someOpParam1") DateType theStart, @OperationParam(name = "someOpParam2") Patient theEnd) {
@OperationParam(name = "someOpParam1") DateType theStart, @OperationParam(name = "someOpParam2") Patient theEnd) {
return null;
}
@ -959,9 +980,9 @@ public class ServerCapabilityStatementProviderDstu3Test {
@SuppressWarnings("unused")
public static class PlainProviderWithExtendedOperationOnNoType {
@Operation(name = "plain", idempotent = true, returnParameters = {@OperationParam(min = 1, max = 2, name = "out1", type = StringType.class)})
@Operation(name = "plain", idempotent = true, returnParameters = { @OperationParam(min = 1, max = 2, name = "out1", type = StringType.class) })
public IBundleProvider everything(javax.servlet.http.HttpServletRequest theServletRequest, @IdParam IdType theId, @OperationParam(name = "start") DateType theStart,
@OperationParam(name = "end") DateType theEnd) {
@OperationParam(name = "end") DateType theEnd) {
return null;
}
@ -972,7 +993,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
@Operation(name = "everything", idempotent = true)
public IBundleProvider everything(javax.servlet.http.HttpServletRequest theServletRequest, @IdParam IdType theId, @OperationParam(name = "start") DateType theStart,
@OperationParam(name = "end") DateType theEnd) {
@OperationParam(name = "end") DateType theEnd) {
return null;
}
@ -989,8 +1010,8 @@ public class ServerCapabilityStatementProviderDstu3Test {
@Description(shortDefinition = "This is a search for stuff!")
@Search
public List<DiagnosticReport> findDiagnosticReportsByPatient(@RequiredParam(name = DiagnosticReport.SP_SUBJECT + '.' + Patient.SP_IDENTIFIER) TokenParam thePatientId,
@OptionalParam(name = DiagnosticReport.SP_CODE) TokenOrListParam theNames, @OptionalParam(name = DiagnosticReport.SP_DATE) DateRangeParam theDateRange,
@IncludeParam(allow = {"DiagnosticReport.result"}) Set<Include> theIncludes) throws Exception {
@OptionalParam(name = DiagnosticReport.SP_CODE) TokenOrListParam theNames, @OptionalParam(name = DiagnosticReport.SP_DATE) DateRangeParam theDateRange,
@IncludeParam(allow = { "DiagnosticReport.result" }) Set<Include> theIncludes) throws Exception {
return null;
}
@ -1021,7 +1042,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
@Search(type = Patient.class)
public Patient findPatient2(
@Description(shortDefinition = "All patients linked to the given patient") @OptionalParam(name = "link", targetTypes = {Patient.class}) ReferenceAndListParam theLink) {
@Description(shortDefinition = "All patients linked to the given patient") @OptionalParam(name = "link", targetTypes = { Patient.class }) ReferenceAndListParam theLink) {
return null;
}
@ -1031,15 +1052,15 @@ public class ServerCapabilityStatementProviderDstu3Test {
public static class SearchProviderWithWhitelist {
@Search(type = Patient.class)
public Patient findPatient1(@Description(shortDefinition = "The organization at which this person is a patient") @RequiredParam(name = Patient.SP_ORGANIZATION, chainWhitelist = {"foo",
"bar"}) ReferenceAndListParam theIdentifier) {
public Patient findPatient1(@Description(shortDefinition = "The organization at which this person is a patient") @RequiredParam(name = Patient.SP_ORGANIZATION, chainWhitelist = { "foo",
"bar" }) ReferenceAndListParam theIdentifier) {
return null;
}
}
@SuppressWarnings("unused")
public static class SearchProviderWithListNoType implements IResourceProvider {
public static class SearchProviderWithListNoType implements IResourceProvider {
@Override
public Class<? extends IBaseResource> getResourceType() {
@ -1055,7 +1076,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
}
@SuppressWarnings("unused")
public static class SearchProviderWithListWithType implements IResourceProvider {
public static class SearchProviderWithListWithType implements IResourceProvider {
@Override
public Class<? extends IBaseResource> getResourceType() {
@ -1063,7 +1084,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
}
@Search(type = Patient.class)
@Search(type=Patient.class)
public List<Patient> findPatient1(@Description(shortDefinition = "The organization at which this person is a patient") @RequiredParam(name = Patient.SP_ORGANIZATION) ReferenceAndListParam theIdentifier) {
return null;
}
@ -1159,6 +1180,50 @@ public class ServerCapabilityStatementProviderDstu3Test {
TestUtil.clearAllStaticFieldsForUnitTest();
}
public static class ProfiledPatientProvider implements IResourceProvider {
@Override
public Class<? extends IBaseResource> getResourceType() {
return PatientSubSub2.class;
}
@Search
public List<PatientSubSub2> find() {
return null;
}
}
public static class MultipleProfilesPatientProvider implements IResourceProvider {
@Override
public Class<? extends IBaseResource> getResourceType() {
return PatientSubSub.class;
}
@Read(type = PatientTripleSub.class)
public PatientTripleSub read(@IdParam IdType theId) {
return null;
}
}
public static final String PATIENT_SUB = "PatientSub";
public static final String PATIENT_SUB_SUB = "PatientSubSub";
public static final String PATIENT_SUB_SUB_2 = "PatientSubSub2";
public static final String PATIENT_TRIPLE_SUB = "PatientTripleSub";
@ResourceDef(id = PATIENT_SUB)
public static class PatientSub extends Patient {}
@ResourceDef(id = PATIENT_SUB_SUB)
public static class PatientSubSub extends PatientSub {}
@ResourceDef(id = PATIENT_SUB_SUB_2)
public static class PatientSubSub2 extends PatientSub {}
@ResourceDef(id = PATIENT_TRIPLE_SUB)
public static class PatientTripleSub extends PatientSubSub {}
private RequestDetails createRequestDetails(RestfulServer theServer) {
ServletRequestDetails retVal = new ServletRequestDetails(null);
retVal.setServer(theServer);

View File

@ -37,6 +37,8 @@ import java.util.Map.Entry;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import ca.uhn.fhir.context.FhirContext;
/*
* #%L
* HAPI FHIR Structures - DSTU2 (FHIR v1.0.0)
@ -115,7 +117,6 @@ public class ServerCapabilityStatementProvider extends BaseServerCapabilityState
}
}
private DateTimeType conformanceDate(RequestDetails theRequestDetails) {
IPrimitiveType<Date> buildDate = getServerConfiguration(theRequestDetails).getConformanceDate();
if (buildDate != null && buildDate.getValue() != null) {
@ -180,13 +181,21 @@ public class ServerCapabilityStatementProvider extends BaseServerCapabilityState
Set<String> operationNames = new HashSet<>();
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = configuration.collectMethodBindings();
Map<String, Class<? extends IBaseResource>> resourceNameToSharedSupertype = configuration.getNameToSharedSupertype();
for (Entry<String, List<BaseMethodBinding<?>>> nextEntry : resourceToMethods.entrySet()) {
if (nextEntry.getKey().isEmpty() == false) {
Set<TypeRestfulInteraction> resourceOps = new HashSet<>();
CapabilityStatementRestResourceComponent resource = rest.addResource();
String resourceName = nextEntry.getKey();
RuntimeResourceDefinition def = configuration.getFhirContext().getResourceDefinition(resourceName);
RuntimeResourceDefinition def;
FhirContext context = configuration.getFhirContext();
if (resourceNameToSharedSupertype.containsKey(resourceName)) {
def = context.getResourceDefinition(resourceNameToSharedSupertype.get(resourceName));
} else {
def = context.getResourceDefinition(resourceName);
}
resource.getTypeElement().setValue(def.getName());
resource.getProfileElement().setValue((def.getResourceProfile(serverBase)));

View File

@ -39,6 +39,8 @@ import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
public class ServerCapabilityStatementProviderR4Test {
private static FhirContext ourCtx;
@ -86,7 +88,7 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new ConditionalProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -115,7 +117,7 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new ProviderWithExtendedOperationReturningBundle());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -142,7 +144,7 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new ProviderWithExtendedOperationReturningBundle());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs) {
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider() {
};
rs.setServerConformanceProvider(sc);
@ -164,7 +166,7 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new InstanceHistoryProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -183,7 +185,7 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new MultiOptionalProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -216,7 +218,7 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new NonConditionalProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -239,7 +241,7 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new MultiTypePatientProvider(), new MultiTypeEncounterProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -307,7 +309,7 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new SearchProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -326,7 +328,7 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new PlainProviderWithExtendedOperationOnNoType());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs) {
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider() {
@Override
public CapabilityStatement getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
return super.getServerConformance(theRequest, createRequestDetails(rs));
@ -366,7 +368,7 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new ProviderWithRequiredAndOptional());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -396,7 +398,7 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new VreadProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -416,7 +418,7 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new ReadProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -436,7 +438,7 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new SearchProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -476,7 +478,7 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new PatientResourceProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -509,7 +511,7 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new SearchProviderWithWhitelist());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -551,7 +553,7 @@ public class ServerCapabilityStatementProviderR4Test {
}
};
rsNoType.registerProvider(new SearchProviderWithListNoType());
ServerCapabilityStatementProvider scNoType = new ServerCapabilityStatementProvider(rsNoType);
ServerCapabilityStatementProvider scNoType = new ServerCapabilityStatementProvider();
rsNoType.setServerConformanceProvider(scNoType);
rsNoType.init(createServletConfig());
@ -568,7 +570,7 @@ public class ServerCapabilityStatementProviderR4Test {
}
};
rsWithType.registerProvider(new SearchProviderWithListWithType());
ServerCapabilityStatementProvider scWithType = new ServerCapabilityStatementProvider(rsWithType);
ServerCapabilityStatementProvider scWithType = new ServerCapabilityStatementProvider();
rsWithType.setServerConformanceProvider(scWithType);
rsWithType.init(createServletConfig());
@ -586,7 +588,7 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new SystemHistoryProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -605,7 +607,7 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new TypeHistoryProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -624,7 +626,7 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new MultiOptionalProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -641,7 +643,7 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new NamedQueryPlainProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -685,7 +687,7 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new NamedQueryResourceProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -728,7 +730,7 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setProviders(new TypeLevelOperationProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs);
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
@ -750,6 +752,26 @@ public class ServerCapabilityStatementProviderR4Test {
assertThat(opDef.getInstance(), is(false));
}
@Test
public void testProfiledResourceStructureDefinitionLinks() throws Exception {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setResourceProviders(new ProfiledPatientProvider(), new MultipleProfilesPatientProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance));
List<CapabilityStatementRestResourceComponent> resources = conformance.getRestFirstRep().getResource();
CapabilityStatementRestResourceComponent patientResource = resources.stream()
.filter(resource -> "Patient".equals(resource.getType()))
.findFirst().get();
assertThat(patientResource.getProfile(), containsString(PATIENT_SUB));
}
private List<String> toOperationIdParts(List<CapabilityStatementRestResourceOperationComponent> theOperation) {
ArrayList<String> retVal = Lists.newArrayList();
for (CapabilityStatementRestResourceOperationComponent next : theOperation) {
@ -1108,4 +1130,48 @@ public class ServerCapabilityStatementProviderR4Test {
}
public static class ProfiledPatientProvider implements IResourceProvider {
@Override
public Class<? extends IBaseResource> getResourceType() {
return PatientSubSub2.class;
}
@Search
public List<PatientSubSub2> find() {
return null;
}
}
public static class MultipleProfilesPatientProvider implements IResourceProvider {
@Override
public Class<? extends IBaseResource> getResourceType() {
return PatientSubSub.class;
}
@Read(type = PatientTripleSub.class)
public PatientTripleSub read(@IdParam IdType theId) {
return null;
}
}
public static final String PATIENT_SUB = "PatientSub";
public static final String PATIENT_SUB_SUB = "PatientSubSub";
public static final String PATIENT_SUB_SUB_2 = "PatientSubSub2";
public static final String PATIENT_TRIPLE_SUB = "PatientTripleSub";
@ResourceDef(id = PATIENT_SUB)
public static class PatientSub extends Patient {}
@ResourceDef(id = PATIENT_SUB_SUB)
public static class PatientSubSub extends PatientSub {}
@ResourceDef(id = PATIENT_SUB_SUB_2)
public static class PatientSubSub2 extends PatientSub {}
@ResourceDef(id = PATIENT_TRIPLE_SUB)
public static class PatientTripleSub extends PatientSubSub {}
}

View File

@ -37,6 +37,8 @@ import java.util.Map.Entry;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import ca.uhn.fhir.context.FhirContext;
/*
* #%L
* HAPI FHIR Structures - DSTU2 (FHIR v1.0.0)
@ -172,13 +174,20 @@ public class ServerCapabilityStatementProvider extends BaseServerCapabilityState
Set<String> operationNames = new HashSet<>();
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = configuration.collectMethodBindings();
Map<String, Class<? extends IBaseResource>> resourceNameToSharedSupertype = configuration.getNameToSharedSupertype();
for (Entry<String, List<BaseMethodBinding<?>>> nextEntry : resourceToMethods.entrySet()) {
if (nextEntry.getKey().isEmpty() == false) {
Set<TypeRestfulInteraction> resourceOps = new HashSet<>();
CapabilityStatementRestResourceComponent resource = rest.addResource();
String resourceName = nextEntry.getKey();
RuntimeResourceDefinition def = configuration.getFhirContext().getResourceDefinition(resourceName);
RuntimeResourceDefinition def;
FhirContext context = configuration.getFhirContext();
if (resourceNameToSharedSupertype.containsKey(resourceName)) {
def = context.getResourceDefinition(resourceNameToSharedSupertype.get(resourceName));
} else {
def = context.getResourceDefinition(resourceName);
}
resource.getTypeElement().setValue(def.getName());
resource.getProfileElement().setValue((def.getResourceProfile(serverBase)));

View File

@ -16,7 +16,6 @@ import ca.uhn.fhir.rest.server.method.SearchMethodBinding;
import ca.uhn.fhir.rest.server.method.SearchParameter;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ValidationResult;
import com.google.common.collect.Lists;
import org.hl7.fhir.instance.model.api.IBaseResource;
@ -40,6 +39,8 @@ import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
public class ServerCapabilityStatementProviderR5Test {
private static FhirContext ourCtx;
@ -748,6 +749,26 @@ public class ServerCapabilityStatementProviderR5Test {
assertThat(opDef.getInstance(), is(false));
}
@Test
public void testProfiledResourceStructureDefinitionLinks() throws Exception {
RestfulServer rs = new RestfulServer(ourCtx);
rs.setResourceProviders(new ProfiledPatientProvider(), new MultipleProfilesPatientProvider());
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider();
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance));
List<CapabilityStatementRestResourceComponent> resources = conformance.getRestFirstRep().getResource();
CapabilityStatementRestResourceComponent patientResource = resources.stream()
.filter(resource -> "Patient".equals(resource.getType()))
.findFirst().get();
assertThat(patientResource.getProfile(), containsString(PATIENT_SUB));
}
private List<String> toOperationIdParts(List<CapabilityStatementRestResourceOperationComponent> theOperation) {
ArrayList<String> retVal = Lists.newArrayList();
for (CapabilityStatementRestResourceOperationComponent next : theOperation) {
@ -1100,4 +1121,48 @@ public class ServerCapabilityStatementProviderR5Test {
}
public static class ProfiledPatientProvider implements IResourceProvider {
@Override
public Class<? extends IBaseResource> getResourceType() {
return PatientSubSub2.class;
}
@Search
public List<PatientSubSub2> find() {
return null;
}
}
public static class MultipleProfilesPatientProvider implements IResourceProvider {
@Override
public Class<? extends IBaseResource> getResourceType() {
return PatientSubSub.class;
}
@Read(type = PatientTripleSub.class)
public PatientTripleSub read(@IdParam IdType theId) {
return null;
}
}
public static final String PATIENT_SUB = "PatientSub";
public static final String PATIENT_SUB_SUB = "PatientSubSub";
public static final String PATIENT_SUB_SUB_2 = "PatientSubSub2";
public static final String PATIENT_TRIPLE_SUB = "PatientTripleSub";
@ResourceDef(id = PATIENT_SUB)
public static class PatientSub extends Patient {}
@ResourceDef(id = PATIENT_SUB_SUB)
public static class PatientSubSub extends PatientSub {}
@ResourceDef(id = PATIENT_SUB_SUB_2)
public static class PatientSubSub2 extends PatientSub {}
@ResourceDef(id = PATIENT_TRIPLE_SUB)
public static class PatientTripleSub extends PatientSubSub {}
}

View File

@ -878,8 +878,7 @@
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<!--<version>6.2.2.jre8</version>-->
<version>7.0.0.jre8</version>
<version>7.4.1.jre8</version>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
@ -958,7 +957,7 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.6.0</version>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
@ -1295,7 +1294,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.6.jre7</version>
<version>42.2.8</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
@ -1665,6 +1664,7 @@
<runOrder>random</runOrder>
<argLine>-Dfile.encoding=UTF-8 -Xmx1024m</argLine>
<forkCount>1.0C</forkCount>
<trimStackTrace>false</trimStackTrace>
</configuration>
</plugin>
<plugin>

View File

@ -17,6 +17,9 @@
<li>Hibernate Core (JPA): 5.4.2.Final -&gt; 5.4.6.Final</li>
<li>Hibernate Search (JPA): 5.11.1.Final -&gt; 5.11.3.Final</li>
<li>Jackson Databind (JPA): 2.9.9 -&gt; 2.9.10 (CVE-2019-16335, CVE-2019-14540)</li>
<li>Commons-DBCP2 (JPA): 2.6.0 -&gt; 2.7.0</li>
<li>Postgresql JDBC Driver (JPA): 42.2.6.jre7 -&gt; 42.2.8</li>
<li>MSSQL JDBC Driver (JPA): 7.0.0.jre8 -&gt; 7.4.1.jre8</li>
<li>Spring Boot (Boot): 2.1.1 -&gt; 2.2.0</li>
</ul>
]]>
@ -489,6 +492,11 @@
The hapi-fhir-testpage-overlay has been updated to support R5 endpoints. Thanks to Dazhi Jiao
for the pull request!
</action>
<action type="add" issue="1088">
The CapabilityStatement generator will now determine supported profiles by navigating the complete
hierarchy of supported resource types, instead of just using the root resource for each type.
Thanks to Stig Døssing for the pull request!
</action>
</release>
<release version="4.0.3" date="2019-09-03" description="Igloo (Point Release)">
<action type="fix">