Fix #379 - Server generated OperationDefinitions should generate
separate definitions for operations that are implemented against multiple resource types
This commit is contained in:
parent
69572f7b3a
commit
8f1e45b3f3
|
@ -156,7 +156,24 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
}
|
}
|
||||||
|
|
||||||
private String createOperationName(OperationMethodBinding theMethodBinding) {
|
private String createOperationName(OperationMethodBinding theMethodBinding) {
|
||||||
return theMethodBinding.getName().substring(1);
|
StringBuilder retVal = new StringBuilder();
|
||||||
|
if (theMethodBinding.getResourceName() != null) {
|
||||||
|
retVal.append(theMethodBinding.getResourceName());
|
||||||
|
}
|
||||||
|
|
||||||
|
retVal.append('_');
|
||||||
|
if (theMethodBinding.isCanOperateAtInstanceLevel()) {
|
||||||
|
retVal.append('i');
|
||||||
|
}
|
||||||
|
if (theMethodBinding.isCanOperateAtServerLevel()) {
|
||||||
|
retVal.append('s');
|
||||||
|
}
|
||||||
|
retVal.append('_');
|
||||||
|
|
||||||
|
// Exclude the leading $
|
||||||
|
retVal.append(theMethodBinding.getName(), 1, theMethodBinding.getName().length());
|
||||||
|
|
||||||
|
return retVal.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -265,7 +282,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
String opName = myOperationBindingToName.get(methodBinding);
|
String opName = myOperationBindingToName.get(methodBinding);
|
||||||
if (operationNames.add(opName)) {
|
if (operationNames.add(opName)) {
|
||||||
// Only add each operation (by name) once
|
// Only add each operation (by name) once
|
||||||
rest.addOperation().setName(opName).getDefinition().setReference("OperationDefinition/" + opName);
|
rest.addOperation().setName(methodBinding.getName().substring(1)).getDefinition().setReference("OperationDefinition/" + opName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,7 +514,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
if (!sharedDescription.isIdempotent()) {
|
if (!sharedDescription.isIdempotent()) {
|
||||||
op.setIdempotent(sharedDescription.isIdempotent());
|
op.setIdempotent(sharedDescription.isIdempotent());
|
||||||
}
|
}
|
||||||
op.setCode(sharedDescription.getName());
|
op.setCode(sharedDescription.getName().substring(1));
|
||||||
if (sharedDescription.isCanOperateAtInstanceLevel()) {
|
if (sharedDescription.isCanOperateAtInstanceLevel()) {
|
||||||
op.setInstance(sharedDescription.isCanOperateAtInstanceLevel());
|
op.setInstance(sharedDescription.isCanOperateAtInstanceLevel());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package ca.uhn.fhir.rest.server;
|
package ca.uhn.fhir.rest.server;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.not;
|
import static org.hamcrest.Matchers.not;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
@ -9,7 +10,9 @@ import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -21,6 +24,8 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.model.api.ExtensionDt;
|
import ca.uhn.fhir.model.api.ExtensionDt;
|
||||||
import ca.uhn.fhir.model.api.Include;
|
import ca.uhn.fhir.model.api.Include;
|
||||||
|
@ -28,10 +33,12 @@ import ca.uhn.fhir.model.api.annotation.Description;
|
||||||
import ca.uhn.fhir.model.dstu2.composite.IdentifierDt;
|
import ca.uhn.fhir.model.dstu2.composite.IdentifierDt;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Conformance;
|
import ca.uhn.fhir.model.dstu2.resource.Conformance;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Conformance.Rest;
|
import ca.uhn.fhir.model.dstu2.resource.Conformance.Rest;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Conformance.RestOperation;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Conformance.RestResource;
|
import ca.uhn.fhir.model.dstu2.resource.Conformance.RestResource;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Conformance.RestResourceSearchParam;
|
import ca.uhn.fhir.model.dstu2.resource.Conformance.RestResourceSearchParam;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Conformance.RestSecurity;
|
import ca.uhn.fhir.model.dstu2.resource.Conformance.RestSecurity;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.DiagnosticReport;
|
import ca.uhn.fhir.model.dstu2.resource.DiagnosticReport;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Encounter;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.OperationDefinition;
|
import ca.uhn.fhir.model.dstu2.resource.OperationDefinition;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.ConditionalDeleteStatusEnum;
|
import ca.uhn.fhir.model.dstu2.valueset.ConditionalDeleteStatusEnum;
|
||||||
|
@ -39,6 +46,7 @@ import ca.uhn.fhir.model.dstu2.valueset.RestfulSecurityServiceEnum;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.SystemRestfulInteractionEnum;
|
import ca.uhn.fhir.model.dstu2.valueset.SystemRestfulInteractionEnum;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.TypeRestfulInteractionEnum;
|
import ca.uhn.fhir.model.dstu2.valueset.TypeRestfulInteractionEnum;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.UnknownContentCodeEnum;
|
import ca.uhn.fhir.model.dstu2.valueset.UnknownContentCodeEnum;
|
||||||
|
import ca.uhn.fhir.model.primitive.CodeDt;
|
||||||
import ca.uhn.fhir.model.primitive.DateDt;
|
import ca.uhn.fhir.model.primitive.DateDt;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.StringDt;
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
|
@ -57,6 +65,7 @@ import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Search;
|
import ca.uhn.fhir.rest.annotation.Search;
|
||||||
import ca.uhn.fhir.rest.annotation.Update;
|
import ca.uhn.fhir.rest.annotation.Update;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Validate;
|
||||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
import ca.uhn.fhir.rest.method.BaseMethodBinding;
|
import ca.uhn.fhir.rest.method.BaseMethodBinding;
|
||||||
import ca.uhn.fhir.rest.method.IParameter;
|
import ca.uhn.fhir.rest.method.IParameter;
|
||||||
|
@ -75,12 +84,6 @@ public class ServerConformanceProviderDstu2Test {
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerConformanceProviderDstu2Test.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerConformanceProviderDstu2Test.class);
|
||||||
|
|
||||||
|
|
||||||
@AfterClass
|
|
||||||
public static void afterClassClearContext() {
|
|
||||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private HttpServletRequest createHttpServletRequest() {
|
private HttpServletRequest createHttpServletRequest() {
|
||||||
HttpServletRequest req = mock(HttpServletRequest.class);
|
HttpServletRequest req = mock(HttpServletRequest.class);
|
||||||
when(req.getRequestURI()).thenReturn("/FhirStorm/fhir/Patient/_search");
|
when(req.getRequestURI()).thenReturn("/FhirStorm/fhir/Patient/_search");
|
||||||
|
@ -89,13 +92,25 @@ public class ServerConformanceProviderDstu2Test {
|
||||||
when(req.getContextPath()).thenReturn("/FhirStorm");
|
when(req.getContextPath()).thenReturn("/FhirStorm");
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServletConfig createServletConfig() {
|
private ServletConfig createServletConfig() {
|
||||||
ServletConfig sc = mock(ServletConfig.class);
|
ServletConfig sc = mock(ServletConfig.class);
|
||||||
when(sc.getServletContext()).thenReturn(null);
|
when(sc.getServletContext()).thenReturn(null);
|
||||||
return sc;
|
return sc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private RestResource findRestResource(Conformance conformance, String wantResource) throws Exception {
|
||||||
|
RestResource resource = null;
|
||||||
|
for (RestResource next : conformance.getRest().get(0).getResource()) {
|
||||||
|
if (next.getType().equals(wantResource)) {
|
||||||
|
resource = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (resource == null) {
|
||||||
|
throw new Exception("Could not find resource: " + wantResource);
|
||||||
|
}
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConditionalOperations() throws Exception {
|
public void testConditionalOperations() throws Exception {
|
||||||
|
|
||||||
|
@ -137,7 +152,7 @@ public class ServerConformanceProviderDstu2Test {
|
||||||
|
|
||||||
assertEquals(1, conformance.getRest().get(0).getOperation().size());
|
assertEquals(1, conformance.getRest().get(0).getOperation().size());
|
||||||
assertEquals("everything", conformance.getRest().get(0).getOperation().get(0).getName());
|
assertEquals("everything", conformance.getRest().get(0).getOperation().get(0).getName());
|
||||||
assertEquals("OperationDefinition/everything", conformance.getRest().get(0).getOperation().get(0).getDefinition().getReference().getValue());
|
assertEquals("OperationDefinition/Patient_i_everything", conformance.getRest().get(0).getOperation().get(0).getDefinition().getReference().getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -152,12 +167,12 @@ public class ServerConformanceProviderDstu2Test {
|
||||||
|
|
||||||
rs.init(createServletConfig());
|
rs.init(createServletConfig());
|
||||||
|
|
||||||
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/everything"));
|
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient_i_everything"));
|
||||||
|
|
||||||
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef);
|
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef);
|
||||||
ourLog.info(conf);
|
ourLog.info(conf);
|
||||||
|
|
||||||
assertEquals("$everything", opDef.getCode());
|
assertEquals("everything", opDef.getCode());
|
||||||
assertEquals(true, opDef.getIdempotent().booleanValue());
|
assertEquals(true, opDef.getIdempotent().booleanValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,6 +195,7 @@ public class ServerConformanceProviderDstu2Test {
|
||||||
assertThat(conf, containsString("<interaction><code value=\"" + TypeRestfulInteractionEnum.HISTORY_INSTANCE.getCode() + "\"/></interaction>"));
|
assertThat(conf, containsString("<interaction><code value=\"" + TypeRestfulInteractionEnum.HISTORY_INSTANCE.getCode() + "\"/></interaction>"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMultiOptionalDocumentation() throws Exception {
|
public void testMultiOptionalDocumentation() throws Exception {
|
||||||
|
|
||||||
|
@ -236,6 +252,71 @@ public class ServerConformanceProviderDstu2Test {
|
||||||
assertNull(res.getConditionalUpdate());
|
assertNull(res.getConditionalUpdate());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** See #379 */
|
||||||
|
@Test
|
||||||
|
public void testOperationAcrossMultipleTypes() throws Exception {
|
||||||
|
RestfulServer rs = new RestfulServer(ourCtx);
|
||||||
|
rs.setProviders(new MultiTypePatientProvider(), new MultiTypeEncounterProvider());
|
||||||
|
|
||||||
|
ServerConformanceProvider sc = new ServerConformanceProvider(rs);
|
||||||
|
rs.setServerConformanceProvider(sc);
|
||||||
|
|
||||||
|
rs.init(createServletConfig());
|
||||||
|
|
||||||
|
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
|
||||||
|
|
||||||
|
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
|
||||||
|
ourLog.info(conf);
|
||||||
|
|
||||||
|
assertEquals(4, conformance.getRest().get(0).getOperation().size());
|
||||||
|
List<String> operationNames = toOperationNames(conformance.getRest().get(0).getOperation());
|
||||||
|
assertThat(operationNames, containsInAnyOrder("someOp", "validate", "someOp", "validate"));
|
||||||
|
|
||||||
|
List<String> operationIdParts = toOperationIdParts(conformance.getRest().get(0).getOperation());
|
||||||
|
assertThat(operationIdParts, containsInAnyOrder("Patient_i_someOp","Encounter_i_someOp","Patient_i_validate","Encounter_i_validate"));
|
||||||
|
|
||||||
|
{
|
||||||
|
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient_i_someOp"));
|
||||||
|
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef));
|
||||||
|
Set<String> types = toStrings(opDef.getType());
|
||||||
|
assertEquals("someOp", opDef.getCode());
|
||||||
|
assertEquals(true, opDef.getInstance());
|
||||||
|
assertEquals(null, opDef.getSystem());
|
||||||
|
assertThat(types, containsInAnyOrder("Patient"));
|
||||||
|
assertEquals(2, opDef.getParameter().size());
|
||||||
|
assertEquals("someOpParam1", opDef.getParameter().get(0).getName());
|
||||||
|
assertEquals("date", opDef.getParameter().get(0).getType());
|
||||||
|
assertEquals("someOpParam2", opDef.getParameter().get(1).getName());
|
||||||
|
assertEquals("Patient", opDef.getParameter().get(1).getType());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Encounter_i_someOp"));
|
||||||
|
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef));
|
||||||
|
Set<String> types = toStrings(opDef.getType());
|
||||||
|
assertEquals("someOp", opDef.getCode());
|
||||||
|
assertEquals(true, opDef.getInstance());
|
||||||
|
assertEquals(null, opDef.getSystem());
|
||||||
|
assertThat(types, containsInAnyOrder("Encounter"));
|
||||||
|
assertEquals(2, opDef.getParameter().size());
|
||||||
|
assertEquals("someOpParam1", opDef.getParameter().get(0).getName());
|
||||||
|
assertEquals("date", opDef.getParameter().get(0).getType());
|
||||||
|
assertEquals("someOpParam2", opDef.getParameter().get(1).getName());
|
||||||
|
assertEquals("Encounter", opDef.getParameter().get(1).getType());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient_i_validate"));
|
||||||
|
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef));
|
||||||
|
Set<String> types = toStrings(opDef.getType());
|
||||||
|
assertEquals("validate", opDef.getCode());
|
||||||
|
assertEquals(true, opDef.getInstance());
|
||||||
|
assertEquals(null, opDef.getSystem());
|
||||||
|
assertThat(types, containsInAnyOrder("Patient"));
|
||||||
|
assertEquals(1, opDef.getParameter().size());
|
||||||
|
assertEquals("resource", opDef.getParameter().get(0).getName());
|
||||||
|
assertEquals("Patient", opDef.getParameter().get(0).getType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOperationDocumentation() throws Exception {
|
public void testOperationDocumentation() throws Exception {
|
||||||
|
|
||||||
|
@ -273,14 +354,14 @@ public class ServerConformanceProviderDstu2Test {
|
||||||
rs.init(createServletConfig());
|
rs.init(createServletConfig());
|
||||||
|
|
||||||
Conformance sconf = sc.getServerConformance(createHttpServletRequest());
|
Conformance sconf = sc.getServerConformance(createHttpServletRequest());
|
||||||
assertEquals("OperationDefinition/plain", sconf.getRest().get(0).getOperation().get(0).getDefinition().getReference().getValue());
|
assertEquals("OperationDefinition/_is_plain", sconf.getRest().get(0).getOperation().get(0).getDefinition().getReference().getValue());
|
||||||
|
|
||||||
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/plain"));
|
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/_is_plain"));
|
||||||
|
|
||||||
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef);
|
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef);
|
||||||
ourLog.info(conf);
|
ourLog.info(conf);
|
||||||
|
|
||||||
assertEquals("$plain", opDef.getCode());
|
assertEquals("plain", opDef.getCode());
|
||||||
assertEquals(true, opDef.getIdempotent().booleanValue());
|
assertEquals(true, opDef.getIdempotent().booleanValue());
|
||||||
assertEquals(3, opDef.getParameter().size());
|
assertEquals(3, opDef.getParameter().size());
|
||||||
assertEquals("start", opDef.getParameter().get(0).getName());
|
assertEquals("start", opDef.getParameter().get(0).getName());
|
||||||
|
@ -336,8 +417,7 @@ public class ServerConformanceProviderDstu2Test {
|
||||||
|
|
||||||
Conformance parsed = ourCtx.newJsonParser().parseResource(Conformance.class, conf);
|
Conformance parsed = ourCtx.newJsonParser().parseResource(Conformance.class, conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProviderWithRequiredAndOptional() throws Exception {
|
public void testProviderWithRequiredAndOptional() throws Exception {
|
||||||
|
|
||||||
|
@ -444,6 +524,40 @@ public class ServerConformanceProviderDstu2Test {
|
||||||
assertThat(conf, containsString("<type value=\"token\"/>"));
|
assertThat(conf, containsString("<type value=\"token\"/>"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See #286
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSearchReferenceParameterDocumentation() throws Exception {
|
||||||
|
|
||||||
|
RestfulServer rs = new RestfulServer(ourCtx);
|
||||||
|
rs.setProviders(new PatientResourceProvider());
|
||||||
|
|
||||||
|
ServerConformanceProvider sc = new ServerConformanceProvider(rs);
|
||||||
|
rs.setServerConformanceProvider(sc);
|
||||||
|
|
||||||
|
rs.init(createServletConfig());
|
||||||
|
|
||||||
|
boolean found = false;
|
||||||
|
Collection<ResourceBinding> resourceBindings = rs.getResourceBindings();
|
||||||
|
for (ResourceBinding resourceBinding : resourceBindings) {
|
||||||
|
if (resourceBinding.getResourceName().equals("Patient")) {
|
||||||
|
List<BaseMethodBinding<?>> methodBindings = resourceBinding.getMethodBindings();
|
||||||
|
SearchMethodBinding binding = (SearchMethodBinding) methodBindings.get(0);
|
||||||
|
SearchParameter param = (SearchParameter) binding.getParameters().get(25);
|
||||||
|
assertEquals("The organization at which this person is a patient", param.getDescription());
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue(found);
|
||||||
|
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
|
||||||
|
|
||||||
|
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
|
||||||
|
ourLog.info(conf);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See #286
|
* See #286
|
||||||
|
@ -484,52 +598,6 @@ public class ServerConformanceProviderDstu2Test {
|
||||||
assertEquals(2, param.getChain().size());
|
assertEquals(2, param.getChain().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
private RestResource findRestResource(Conformance conformance, String wantResource) throws Exception {
|
|
||||||
RestResource resource = null;
|
|
||||||
for (RestResource next : conformance.getRest().get(0).getResource()) {
|
|
||||||
if (next.getType().equals(wantResource)) {
|
|
||||||
resource = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (resource == null) {
|
|
||||||
throw new Exception("Could not find resource: " + wantResource);
|
|
||||||
}
|
|
||||||
return resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See #286
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testSearchReferenceParameterDocumentation() throws Exception {
|
|
||||||
|
|
||||||
RestfulServer rs = new RestfulServer(ourCtx);
|
|
||||||
rs.setProviders(new PatientResourceProvider());
|
|
||||||
|
|
||||||
ServerConformanceProvider sc = new ServerConformanceProvider(rs);
|
|
||||||
rs.setServerConformanceProvider(sc);
|
|
||||||
|
|
||||||
rs.init(createServletConfig());
|
|
||||||
|
|
||||||
boolean found = false;
|
|
||||||
Collection<ResourceBinding> resourceBindings = rs.getResourceBindings();
|
|
||||||
for (ResourceBinding resourceBinding : resourceBindings) {
|
|
||||||
if (resourceBinding.getResourceName().equals("Patient")) {
|
|
||||||
List<BaseMethodBinding<?>> methodBindings = resourceBinding.getMethodBindings();
|
|
||||||
SearchMethodBinding binding = (SearchMethodBinding) methodBindings.get(0);
|
|
||||||
SearchParameter param = (SearchParameter) binding.getParameters().get(25);
|
|
||||||
assertEquals("The organization at which this person is a patient", param.getDescription());
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assertTrue(found);
|
|
||||||
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
|
|
||||||
|
|
||||||
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
|
|
||||||
ourLog.info(conf);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSystemHistorySupported() throws Exception {
|
public void testSystemHistorySupported() throws Exception {
|
||||||
|
|
||||||
|
@ -585,6 +653,35 @@ public class ServerConformanceProviderDstu2Test {
|
||||||
ValidationResult result = ourCtx.newValidator().validateWithResult(conformance);
|
ValidationResult result = ourCtx.newValidator().validateWithResult(conformance);
|
||||||
assertTrue(result.getMessages().toString(), result.isSuccessful());
|
assertTrue(result.getMessages().toString(), result.isSuccessful());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<String> toOperationIdParts(List<RestOperation> theOperation) {
|
||||||
|
ArrayList<String> retVal = Lists.newArrayList();
|
||||||
|
for (RestOperation next : theOperation) {
|
||||||
|
retVal.add(next.getDefinition().getReference().getIdPart());
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> toOperationNames(List<RestOperation> theOperation) {
|
||||||
|
ArrayList<String> retVal = Lists.newArrayList();
|
||||||
|
for (RestOperation next : theOperation) {
|
||||||
|
retVal.add(next.getName());
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> toStrings(List<? extends CodeDt> theType) {
|
||||||
|
HashSet<String> retVal = new HashSet<String>();
|
||||||
|
for (CodeDt next : theType) {
|
||||||
|
retVal.add(next.getValueAsString());
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClassClearContext() {
|
||||||
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
|
}
|
||||||
|
|
||||||
public static class ConditionalProvider implements IResourceProvider {
|
public static class ConditionalProvider implements IResourceProvider {
|
||||||
|
|
||||||
|
@ -635,6 +732,46 @@ public class ServerConformanceProviderDstu2Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class MultiTypeEncounterProvider implements IResourceProvider {
|
||||||
|
|
||||||
|
@Operation(name = "someOp")
|
||||||
|
public ca.uhn.fhir.rest.server.IBundleProvider everything(javax.servlet.http.HttpServletRequest theServletRequest, @IdParam IdDt theId,
|
||||||
|
@OperationParam(name = "someOpParam1") DateDt theStart, @OperationParam(name = "someOpParam2") Encounter theEnd) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends IBaseResource> getResourceType() {
|
||||||
|
return Encounter.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Validate
|
||||||
|
public ca.uhn.fhir.rest.server.IBundleProvider validate(javax.servlet.http.HttpServletRequest theServletRequest, @IdParam IdDt theId, @ResourceParam Encounter thePatient) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MultiTypePatientProvider implements IResourceProvider {
|
||||||
|
|
||||||
|
@Operation(name = "someOp")
|
||||||
|
public ca.uhn.fhir.rest.server.IBundleProvider everything(javax.servlet.http.HttpServletRequest theServletRequest, @IdParam IdDt theId,
|
||||||
|
@OperationParam(name = "someOpParam1") DateDt theStart, @OperationParam(name = "someOpParam2") Patient theEnd) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends IBaseResource> getResourceType() {
|
||||||
|
return Patient.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Validate
|
||||||
|
public ca.uhn.fhir.rest.server.IBundleProvider validate(javax.servlet.http.HttpServletRequest theServletRequest, @IdParam IdDt theId, @ResourceParam Patient thePatient) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public static class NonConditionalProvider implements IResourceProvider {
|
public static class NonConditionalProvider implements IResourceProvider {
|
||||||
|
|
||||||
@Create
|
@Create
|
||||||
|
|
|
@ -77,6 +77,7 @@ import ca.uhn.fhir.rest.method.OperationParameter;
|
||||||
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
|
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
|
||||||
import ca.uhn.fhir.rest.method.SearchMethodBinding;
|
import ca.uhn.fhir.rest.method.SearchMethodBinding;
|
||||||
import ca.uhn.fhir.rest.method.SearchParameter;
|
import ca.uhn.fhir.rest.method.SearchParameter;
|
||||||
|
import ca.uhn.fhir.rest.method.ValidateMethodBindingDstu3;
|
||||||
import ca.uhn.fhir.rest.server.Constants;
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
import ca.uhn.fhir.rest.server.IServerConformanceProvider;
|
import ca.uhn.fhir.rest.server.IServerConformanceProvider;
|
||||||
import ca.uhn.fhir.rest.server.ResourceBinding;
|
import ca.uhn.fhir.rest.server.ResourceBinding;
|
||||||
|
@ -173,7 +174,24 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
}
|
}
|
||||||
|
|
||||||
private String createOperationName(OperationMethodBinding theMethodBinding) {
|
private String createOperationName(OperationMethodBinding theMethodBinding) {
|
||||||
return theMethodBinding.getName().substring(1);
|
StringBuilder retVal = new StringBuilder();
|
||||||
|
if (theMethodBinding.getResourceName() != null) {
|
||||||
|
retVal.append(theMethodBinding.getResourceName());
|
||||||
|
}
|
||||||
|
|
||||||
|
retVal.append('_');
|
||||||
|
if (theMethodBinding.isCanOperateAtInstanceLevel()) {
|
||||||
|
retVal.append('i');
|
||||||
|
}
|
||||||
|
if (theMethodBinding.isCanOperateAtServerLevel()) {
|
||||||
|
retVal.append('s');
|
||||||
|
}
|
||||||
|
retVal.append('_');
|
||||||
|
|
||||||
|
// Exclude the leading $
|
||||||
|
retVal.append(theMethodBinding.getName(), 1, theMethodBinding.getName().length());
|
||||||
|
|
||||||
|
return retVal.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -289,7 +307,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
String opName = myOperationBindingToName.get(methodBinding);
|
String opName = myOperationBindingToName.get(methodBinding);
|
||||||
if (operationNames.add(opName)) {
|
if (operationNames.add(opName)) {
|
||||||
// Only add each operation (by name) once
|
// Only add each operation (by name) once
|
||||||
rest.addOperation().setName(opName).setDefinition(new Reference("OperationDefinition/" + opName));
|
rest.addOperation().setName(methodBinding.getName().substring(1)).setDefinition(new Reference("OperationDefinition/" + opName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,7 +535,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
if (!sharedDescription.isIdempotent()) {
|
if (!sharedDescription.isIdempotent()) {
|
||||||
op.setIdempotent(sharedDescription.isIdempotent());
|
op.setIdempotent(sharedDescription.isIdempotent());
|
||||||
}
|
}
|
||||||
op.setCode(createOperationName(sharedDescription));
|
op.setCode(sharedDescription.getName().substring(1));
|
||||||
if (sharedDescription.isCanOperateAtInstanceLevel()) {
|
if (sharedDescription.isCanOperateAtInstanceLevel()) {
|
||||||
op.setInstance(sharedDescription.isCanOperateAtInstanceLevel());
|
op.setInstance(sharedDescription.isCanOperateAtInstanceLevel());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.hl7.fhir.dstu3.hapi.rest.server;
|
package org.hl7.fhir.dstu3.hapi.rest.server;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.not;
|
import static org.hamcrest.Matchers.not;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
@ -9,31 +10,37 @@ import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.servlet.ServletConfig;
|
import javax.servlet.ServletConfig;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.hl7.fhir.dstu3.hapi.rest.server.ServerConformanceProvider;
|
import org.hl7.fhir.dstu3.model.CodeType;
|
||||||
import org.hl7.fhir.dstu3.model.Conformance;
|
import org.hl7.fhir.dstu3.model.Conformance;
|
||||||
import org.hl7.fhir.dstu3.model.DateType;
|
|
||||||
import org.hl7.fhir.dstu3.model.DiagnosticReport;
|
|
||||||
import org.hl7.fhir.dstu3.model.IdType;
|
|
||||||
import org.hl7.fhir.dstu3.model.OperationDefinition;
|
|
||||||
import org.hl7.fhir.dstu3.model.Patient;
|
|
||||||
import org.hl7.fhir.dstu3.model.StringType;
|
|
||||||
import org.hl7.fhir.dstu3.model.Conformance.ConditionalDeleteStatus;
|
import org.hl7.fhir.dstu3.model.Conformance.ConditionalDeleteStatus;
|
||||||
import org.hl7.fhir.dstu3.model.Conformance.ConformanceRestComponent;
|
import org.hl7.fhir.dstu3.model.Conformance.ConformanceRestComponent;
|
||||||
|
import org.hl7.fhir.dstu3.model.Conformance.ConformanceRestOperationComponent;
|
||||||
import org.hl7.fhir.dstu3.model.Conformance.ConformanceRestResourceComponent;
|
import org.hl7.fhir.dstu3.model.Conformance.ConformanceRestResourceComponent;
|
||||||
import org.hl7.fhir.dstu3.model.Conformance.ConformanceRestResourceSearchParamComponent;
|
import org.hl7.fhir.dstu3.model.Conformance.ConformanceRestResourceSearchParamComponent;
|
||||||
import org.hl7.fhir.dstu3.model.Conformance.SystemRestfulInteraction;
|
import org.hl7.fhir.dstu3.model.Conformance.SystemRestfulInteraction;
|
||||||
import org.hl7.fhir.dstu3.model.Conformance.TypeRestfulInteraction;
|
import org.hl7.fhir.dstu3.model.Conformance.TypeRestfulInteraction;
|
||||||
|
import org.hl7.fhir.dstu3.model.DateType;
|
||||||
|
import org.hl7.fhir.dstu3.model.DiagnosticReport;
|
||||||
|
import org.hl7.fhir.dstu3.model.Encounter;
|
||||||
|
import org.hl7.fhir.dstu3.model.IdType;
|
||||||
|
import org.hl7.fhir.dstu3.model.OperationDefinition;
|
||||||
|
import org.hl7.fhir.dstu3.model.Patient;
|
||||||
|
import org.hl7.fhir.dstu3.model.StringType;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.model.api.Include;
|
import ca.uhn.fhir.model.api.Include;
|
||||||
import ca.uhn.fhir.model.api.annotation.Description;
|
import ca.uhn.fhir.model.api.annotation.Description;
|
||||||
|
@ -51,6 +58,7 @@ import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Search;
|
import ca.uhn.fhir.rest.annotation.Search;
|
||||||
import ca.uhn.fhir.rest.annotation.Update;
|
import ca.uhn.fhir.rest.annotation.Update;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Validate;
|
||||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
import ca.uhn.fhir.rest.method.BaseMethodBinding;
|
import ca.uhn.fhir.rest.method.BaseMethodBinding;
|
||||||
import ca.uhn.fhir.rest.method.IParameter;
|
import ca.uhn.fhir.rest.method.IParameter;
|
||||||
|
@ -71,10 +79,6 @@ public class ServerConformanceProviderDstu3Test {
|
||||||
|
|
||||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerConformanceProviderDstu3Test.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerConformanceProviderDstu3Test.class);
|
||||||
@AfterClass
|
|
||||||
public static void afterClassClearContext() {
|
|
||||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
private HttpServletRequest createHttpServletRequest() {
|
private HttpServletRequest createHttpServletRequest() {
|
||||||
HttpServletRequest req = mock(HttpServletRequest.class);
|
HttpServletRequest req = mock(HttpServletRequest.class);
|
||||||
|
@ -91,6 +95,19 @@ public class ServerConformanceProviderDstu3Test {
|
||||||
return sc;
|
return sc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ConformanceRestResourceComponent findRestResource(Conformance conformance, String wantResource) throws Exception {
|
||||||
|
ConformanceRestResourceComponent resource = null;
|
||||||
|
for (ConformanceRestResourceComponent next : conformance.getRest().get(0).getResource()) {
|
||||||
|
if (next.getType().equals(wantResource)) {
|
||||||
|
resource = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (resource == null) {
|
||||||
|
throw new Exception("Could not find resource: " + wantResource);
|
||||||
|
}
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConditionalOperations() throws Exception {
|
public void testConditionalOperations() throws Exception {
|
||||||
|
|
||||||
|
@ -149,7 +166,7 @@ public class ServerConformanceProviderDstu3Test {
|
||||||
|
|
||||||
rs.init(createServletConfig());
|
rs.init(createServletConfig());
|
||||||
|
|
||||||
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/everything"));
|
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient_i_everything"));
|
||||||
|
|
||||||
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef);
|
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef);
|
||||||
ourLog.info(conf);
|
ourLog.info(conf);
|
||||||
|
@ -233,6 +250,79 @@ public class ServerConformanceProviderDstu3Test {
|
||||||
assertNull(res.getConditionalUpdateElement().getValue());
|
assertNull(res.getConditionalUpdateElement().getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<String> toOperationIdParts(List<ConformanceRestOperationComponent> theOperation) {
|
||||||
|
ArrayList<String> retVal = Lists.newArrayList();
|
||||||
|
for (ConformanceRestOperationComponent next : theOperation) {
|
||||||
|
retVal.add(next.getDefinition().getReferenceElement().getIdPart());
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** See #379 */
|
||||||
|
@Test
|
||||||
|
public void testOperationAcrossMultipleTypes() throws Exception {
|
||||||
|
RestfulServer rs = new RestfulServer(ourCtx);
|
||||||
|
rs.setProviders(new MultiTypePatientProvider(), new MultiTypeEncounterProvider());
|
||||||
|
|
||||||
|
ServerConformanceProvider sc = new ServerConformanceProvider(rs);
|
||||||
|
rs.setServerConformanceProvider(sc);
|
||||||
|
|
||||||
|
rs.init(createServletConfig());
|
||||||
|
|
||||||
|
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
|
||||||
|
|
||||||
|
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
|
||||||
|
ourLog.info(conf);
|
||||||
|
|
||||||
|
assertEquals(4, conformance.getRest().get(0).getOperation().size());
|
||||||
|
List<String> operationNames = toOperationNames(conformance.getRest().get(0).getOperation());
|
||||||
|
assertThat(operationNames, containsInAnyOrder("someOp", "validate", "someOp", "validate"));
|
||||||
|
|
||||||
|
List<String> operationIdParts = toOperationIdParts(conformance.getRest().get(0).getOperation());
|
||||||
|
assertThat(operationIdParts, containsInAnyOrder("Patient_i_someOp","Encounter_i_someOp","Patient_i_validate","Encounter_i_validate"));
|
||||||
|
|
||||||
|
{
|
||||||
|
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient_i_someOp"));
|
||||||
|
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef));
|
||||||
|
Set<String> types = toStrings(opDef.getType());
|
||||||
|
assertEquals("someOp", opDef.getCode());
|
||||||
|
assertEquals(true, opDef.getInstance());
|
||||||
|
assertEquals(false, opDef.getSystem());
|
||||||
|
assertThat(types, containsInAnyOrder("Patient"));
|
||||||
|
assertEquals(2, opDef.getParameter().size());
|
||||||
|
assertEquals("someOpParam1", opDef.getParameter().get(0).getName());
|
||||||
|
assertEquals("date", opDef.getParameter().get(0).getType());
|
||||||
|
assertEquals("someOpParam2", opDef.getParameter().get(1).getName());
|
||||||
|
assertEquals("Patient", opDef.getParameter().get(1).getType());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Encounter_i_someOp"));
|
||||||
|
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef));
|
||||||
|
Set<String> types = toStrings(opDef.getType());
|
||||||
|
assertEquals("someOp", opDef.getCode());
|
||||||
|
assertEquals(true, opDef.getInstance());
|
||||||
|
assertEquals(false, opDef.getSystem());
|
||||||
|
assertThat(types, containsInAnyOrder("Encounter"));
|
||||||
|
assertEquals(2, opDef.getParameter().size());
|
||||||
|
assertEquals("someOpParam1", opDef.getParameter().get(0).getName());
|
||||||
|
assertEquals("date", opDef.getParameter().get(0).getType());
|
||||||
|
assertEquals("someOpParam2", opDef.getParameter().get(1).getName());
|
||||||
|
assertEquals("Encounter", opDef.getParameter().get(1).getType());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient_i_validate"));
|
||||||
|
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef));
|
||||||
|
Set<String> types = toStrings(opDef.getType());
|
||||||
|
assertEquals("validate", opDef.getCode());
|
||||||
|
assertEquals(true, opDef.getInstance());
|
||||||
|
assertEquals(false, opDef.getSystem());
|
||||||
|
assertThat(types, containsInAnyOrder("Patient"));
|
||||||
|
assertEquals(1, opDef.getParameter().size());
|
||||||
|
assertEquals("resource", opDef.getParameter().get(0).getName());
|
||||||
|
assertEquals("Patient", opDef.getParameter().get(0).getType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOperationDocumentation() throws Exception {
|
public void testOperationDocumentation() throws Exception {
|
||||||
|
|
||||||
|
@ -268,7 +358,7 @@ public class ServerConformanceProviderDstu3Test {
|
||||||
|
|
||||||
rs.init(createServletConfig());
|
rs.init(createServletConfig());
|
||||||
|
|
||||||
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/plain"));
|
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/_is_plain"));
|
||||||
|
|
||||||
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef);
|
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef);
|
||||||
ourLog.info(conf);
|
ourLog.info(conf);
|
||||||
|
@ -394,58 +484,6 @@ public class ServerConformanceProviderDstu3Test {
|
||||||
assertThat(conf, containsString("<type value=\"token\"/>"));
|
assertThat(conf, containsString("<type value=\"token\"/>"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* See #286
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testSearchReferenceParameterWithWhitelistDocumentation() throws Exception {
|
|
||||||
|
|
||||||
RestfulServer rs = new RestfulServer(ourCtx);
|
|
||||||
rs.setProviders(new SearchProviderWithWhitelist());
|
|
||||||
|
|
||||||
ServerConformanceProvider sc = new ServerConformanceProvider(rs);
|
|
||||||
rs.setServerConformanceProvider(sc);
|
|
||||||
|
|
||||||
rs.init(createServletConfig());
|
|
||||||
|
|
||||||
boolean found = false;
|
|
||||||
Collection<ResourceBinding> resourceBindings = rs.getResourceBindings();
|
|
||||||
for (ResourceBinding resourceBinding : resourceBindings) {
|
|
||||||
if (resourceBinding.getResourceName().equals("Patient")) {
|
|
||||||
List<BaseMethodBinding<?>> methodBindings = resourceBinding.getMethodBindings();
|
|
||||||
SearchMethodBinding binding = (SearchMethodBinding) methodBindings.get(0);
|
|
||||||
SearchParameter param = (SearchParameter) binding.getParameters().get(0);
|
|
||||||
assertEquals("The organization at which this person is a patient", param.getDescription());
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assertTrue(found);
|
|
||||||
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
|
|
||||||
|
|
||||||
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
|
|
||||||
ourLog.info(conf);
|
|
||||||
|
|
||||||
ConformanceRestResourceComponent resource = findRestResource(conformance, "Patient");
|
|
||||||
|
|
||||||
ConformanceRestResourceSearchParamComponent param = resource.getSearchParam().get(0);
|
|
||||||
assertEquals("bar", param.getChain().get(0).getValue());
|
|
||||||
assertEquals("foo", param.getChain().get(1).getValue());
|
|
||||||
assertEquals(2, param.getChain().size());
|
|
||||||
}
|
|
||||||
|
|
||||||
private ConformanceRestResourceComponent findRestResource(Conformance conformance, String wantResource) throws Exception {
|
|
||||||
ConformanceRestResourceComponent resource = null;
|
|
||||||
for (ConformanceRestResourceComponent next : conformance.getRest().get(0).getResource()) {
|
|
||||||
if (next.getType().equals(wantResource)) {
|
|
||||||
resource = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (resource == null) {
|
|
||||||
throw new Exception("Could not find resource: " + wantResource);
|
|
||||||
}
|
|
||||||
return resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See #286
|
* See #286
|
||||||
|
@ -480,6 +518,45 @@ public class ServerConformanceProviderDstu3Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See #286
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSearchReferenceParameterWithWhitelistDocumentation() throws Exception {
|
||||||
|
|
||||||
|
RestfulServer rs = new RestfulServer(ourCtx);
|
||||||
|
rs.setProviders(new SearchProviderWithWhitelist());
|
||||||
|
|
||||||
|
ServerConformanceProvider sc = new ServerConformanceProvider(rs);
|
||||||
|
rs.setServerConformanceProvider(sc);
|
||||||
|
|
||||||
|
rs.init(createServletConfig());
|
||||||
|
|
||||||
|
boolean found = false;
|
||||||
|
Collection<ResourceBinding> resourceBindings = rs.getResourceBindings();
|
||||||
|
for (ResourceBinding resourceBinding : resourceBindings) {
|
||||||
|
if (resourceBinding.getResourceName().equals("Patient")) {
|
||||||
|
List<BaseMethodBinding<?>> methodBindings = resourceBinding.getMethodBindings();
|
||||||
|
SearchMethodBinding binding = (SearchMethodBinding) methodBindings.get(0);
|
||||||
|
SearchParameter param = (SearchParameter) binding.getParameters().get(0);
|
||||||
|
assertEquals("The organization at which this person is a patient", param.getDescription());
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue(found);
|
||||||
|
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
|
||||||
|
|
||||||
|
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
|
||||||
|
ourLog.info(conf);
|
||||||
|
|
||||||
|
ConformanceRestResourceComponent resource = findRestResource(conformance, "Patient");
|
||||||
|
|
||||||
|
ConformanceRestResourceSearchParamComponent param = resource.getSearchParam().get(0);
|
||||||
|
assertEquals("bar", param.getChain().get(0).getValue());
|
||||||
|
assertEquals("foo", param.getChain().get(1).getValue());
|
||||||
|
assertEquals(2, param.getChain().size());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSystemHistorySupported() throws Exception {
|
public void testSystemHistorySupported() throws Exception {
|
||||||
|
|
||||||
|
@ -536,6 +613,27 @@ public class ServerConformanceProviderDstu3Test {
|
||||||
assertTrue(result.getMessages().toString(), result.isSuccessful());
|
assertTrue(result.getMessages().toString(), result.isSuccessful());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<String> toOperationNames(List<ConformanceRestOperationComponent> theOperation) {
|
||||||
|
ArrayList<String> retVal = Lists.newArrayList();
|
||||||
|
for (ConformanceRestOperationComponent next : theOperation) {
|
||||||
|
retVal.add(next.getName());
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> toStrings(List<CodeType> theType) {
|
||||||
|
HashSet<String> retVal = new HashSet<String>();
|
||||||
|
for (CodeType next : theType) {
|
||||||
|
retVal.add(next.getValueAsString());
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClassClearContext() {
|
||||||
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
|
}
|
||||||
|
|
||||||
public static class ConditionalProvider implements IResourceProvider {
|
public static class ConditionalProvider implements IResourceProvider {
|
||||||
|
|
||||||
@Create
|
@Create
|
||||||
|
@ -579,7 +677,48 @@ public class ServerConformanceProviderDstu3Test {
|
||||||
public static class MultiOptionalProvider {
|
public static class MultiOptionalProvider {
|
||||||
|
|
||||||
@Search(type = Patient.class)
|
@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) {
|
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) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MultiTypeEncounterProvider implements IResourceProvider {
|
||||||
|
|
||||||
|
@Operation(name = "someOp")
|
||||||
|
public ca.uhn.fhir.rest.server.IBundleProvider everything(javax.servlet.http.HttpServletRequest theServletRequest, @IdParam IdType theId,
|
||||||
|
@OperationParam(name = "someOpParam1") DateType theStart, @OperationParam(name = "someOpParam2") Encounter theEnd) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends IBaseResource> getResourceType() {
|
||||||
|
return Encounter.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Validate
|
||||||
|
public ca.uhn.fhir.rest.server.IBundleProvider validate(javax.servlet.http.HttpServletRequest theServletRequest, @IdParam IdType theId, @ResourceParam Encounter thePatient) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MultiTypePatientProvider implements IResourceProvider {
|
||||||
|
|
||||||
|
@Operation(name = "someOp")
|
||||||
|
public ca.uhn.fhir.rest.server.IBundleProvider everything(javax.servlet.http.HttpServletRequest theServletRequest, @IdParam IdType theId,
|
||||||
|
@OperationParam(name = "someOpParam1") DateType theStart, @OperationParam(name = "someOpParam2") Patient theEnd) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends IBaseResource> getResourceType() {
|
||||||
|
return Patient.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Validate
|
||||||
|
public ca.uhn.fhir.rest.server.IBundleProvider validate(javax.servlet.http.HttpServletRequest theServletRequest, @IdParam IdType theId, @ResourceParam Patient thePatient) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -612,7 +751,8 @@ public class ServerConformanceProviderDstu3Test {
|
||||||
public static class PlainProviderWithExtendedOperationOnNoType {
|
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 ca.uhn.fhir.rest.server.IBundleProvider everything(javax.servlet.http.HttpServletRequest theServletRequest, @IdParam IdType theId, @OperationParam(name = "start") DateType theStart, @OperationParam(name = "end") DateType theEnd) {
|
public ca.uhn.fhir.rest.server.IBundleProvider everything(javax.servlet.http.HttpServletRequest theServletRequest, @IdParam IdType theId, @OperationParam(name = "start") DateType theStart,
|
||||||
|
@OperationParam(name = "end") DateType theEnd) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -621,7 +761,8 @@ public class ServerConformanceProviderDstu3Test {
|
||||||
public static class ProviderWithExtendedOperationReturningBundle implements IResourceProvider {
|
public static class ProviderWithExtendedOperationReturningBundle implements IResourceProvider {
|
||||||
|
|
||||||
@Operation(name = "everything", idempotent = true)
|
@Operation(name = "everything", idempotent = true)
|
||||||
public ca.uhn.fhir.rest.server.IBundleProvider everything(javax.servlet.http.HttpServletRequest theServletRequest, @IdParam IdType theId, @OperationParam(name = "start") DateType theStart, @OperationParam(name = "end") DateType theEnd) {
|
public ca.uhn.fhir.rest.server.IBundleProvider everything(javax.servlet.http.HttpServletRequest theServletRequest, @IdParam IdType theId, @OperationParam(name = "start") DateType theStart,
|
||||||
|
@OperationParam(name = "end") DateType theEnd) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -636,16 +777,14 @@ public class ServerConformanceProviderDstu3Test {
|
||||||
|
|
||||||
@Description(shortDefinition = "This is a search for stuff!")
|
@Description(shortDefinition = "This is a search for stuff!")
|
||||||
@Search
|
@Search
|
||||||
public List<DiagnosticReport> findDiagnosticReportsByPatient(@RequiredParam(name = DiagnosticReport.SP_SUBJECT + '.' + Patient.SP_IDENTIFIER) TokenParam thePatientId, @OptionalParam(name = DiagnosticReport.SP_CODE) TokenOrListParam theNames,
|
public List<DiagnosticReport> findDiagnosticReportsByPatient(@RequiredParam(name = DiagnosticReport.SP_SUBJECT + '.' + Patient.SP_IDENTIFIER) TokenParam thePatientId,
|
||||||
@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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by dsotnikov on 2/25/2014.
|
|
||||||
*/
|
|
||||||
public static class ReadProvider {
|
public static class ReadProvider {
|
||||||
|
|
||||||
@Search(type = Patient.class)
|
@Search(type = Patient.class)
|
||||||
|
@ -668,7 +807,8 @@ public class ServerConformanceProviderDstu3Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Search(type = Patient.class)
|
@Search(type = Patient.class)
|
||||||
public Patient findPatient2(@Description(shortDefinition = "All patients linked to the given patient") @OptionalParam(name = "link", targetTypes = { Patient.class }) ReferenceAndListParam theLink) {
|
public Patient findPatient2(
|
||||||
|
@Description(shortDefinition = "All patients linked to the given patient") @OptionalParam(name = "link", targetTypes = { Patient.class }) ReferenceAndListParam theLink) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -677,10 +817,8 @@ public class ServerConformanceProviderDstu3Test {
|
||||||
public static class SearchProviderWithWhitelist {
|
public static class SearchProviderWithWhitelist {
|
||||||
|
|
||||||
@Search(type = Patient.class)
|
@Search(type = Patient.class)
|
||||||
public Patient findPatient1(
|
public Patient findPatient1(@Description(shortDefinition = "The organization at which this person is a patient") @RequiredParam(name = Patient.SP_ORGANIZATION, chainWhitelist = { "foo",
|
||||||
@Description(shortDefinition = "The organization at which this person is a patient")
|
"bar" }) ReferenceAndListParam theIdentifier) {
|
||||||
@RequiredParam(name = Patient.SP_ORGANIZATION, chainWhitelist= {"foo", "bar"})
|
|
||||||
ReferenceAndListParam theIdentifier) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -329,9 +329,15 @@
|
||||||
that are defined within resource/plain providers incorrectly stated that
|
that are defined within resource/plain providers incorrectly stated that
|
||||||
the maximum cardinality was "*" for non-collection types with no explicit
|
the maximum cardinality was "*" for non-collection types with no explicit
|
||||||
maximum stated, which is not the behaviour that the JavaDoc on the
|
maximum stated, which is not the behaviour that the JavaDoc on the
|
||||||
<![CDATA[@OperationParam]] annotation describes. Thanks to Michael Lawley
|
<![CDATA[@OperationParam]]> annotation describes. Thanks to Michael Lawley
|
||||||
for reporting!
|
for reporting!
|
||||||
</action>
|
</action>
|
||||||
|
<action type="fix" issue="379">
|
||||||
|
Operations that are defined on multiple resource provider types with
|
||||||
|
the same name (e.g. "$everything") are now automatically exposed by the server
|
||||||
|
as separate OperationDefinition resources per resource type. Thanks to
|
||||||
|
Michael Lawley for reporting!
|
||||||
|
</action>
|
||||||
</release>
|
</release>
|
||||||
<release version="1.5" date="2016-04-20">
|
<release version="1.5" date="2016-04-20">
|
||||||
<action type="fix" issue="339">
|
<action type="fix" issue="339">
|
||||||
|
|
Loading…
Reference in New Issue