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.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.servlet.ServletConfig; import javax.servlet.http.HttpServletRequest; import org.hl7.fhir.dstu3.model.CodeType; import org.hl7.fhir.dstu3.model.CapabilityStatement; import org.hl7.fhir.dstu3.model.CapabilityStatement.ConditionalDeleteStatus; import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestComponent; import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestOperationComponent; import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestResourceComponent; import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent; import org.hl7.fhir.dstu3.model.CapabilityStatement.SystemRestfulInteraction; import org.hl7.fhir.dstu3.model.CapabilityStatement.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.junit.AfterClass; import org.junit.Test; import com.google.common.collect.Lists; 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.rest.annotation.ConditionalUrlParam; import ca.uhn.fhir.rest.annotation.Create; import ca.uhn.fhir.rest.annotation.Delete; import ca.uhn.fhir.rest.annotation.History; import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.IncludeParam; import ca.uhn.fhir.rest.annotation.Operation; import ca.uhn.fhir.rest.annotation.OperationParam; import ca.uhn.fhir.rest.annotation.OptionalParam; import ca.uhn.fhir.rest.annotation.Read; import ca.uhn.fhir.rest.annotation.RequiredParam; import ca.uhn.fhir.rest.annotation.ResourceParam; import ca.uhn.fhir.rest.annotation.Search; 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.method.BaseMethodBinding; import ca.uhn.fhir.rest.method.IParameter; import ca.uhn.fhir.rest.method.SearchMethodBinding; import ca.uhn.fhir.rest.method.SearchParameter; import ca.uhn.fhir.rest.param.DateRangeParam; import ca.uhn.fhir.rest.param.ReferenceAndListParam; import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.param.TokenOrListParam; import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.ResourceBinding; import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.ValidationResult; public class ServerCapabilityStatementProviderDstu3Test { private static FhirContext ourCtx; private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerCapabilityStatementProviderDstu3Test.class); private static FhirValidator ourValidator; static { ourCtx = FhirContext.forDstu3(); ourValidator = ourCtx.newValidator(); ourValidator.setValidateAgainstStandardSchema(true); ourValidator.setValidateAgainstStandardSchematron(true); } private HttpServletRequest createHttpServletRequest() { HttpServletRequest req = mock(HttpServletRequest.class); when(req.getRequestURI()).thenReturn("/FhirStorm/fhir/Patient/_search"); when(req.getServletPath()).thenReturn("/fhir"); when(req.getRequestURL()).thenReturn(new StringBuffer().append("http://fhirstorm.dyndns.org:8080/FhirStorm/fhir/Patient/_search")); when(req.getContextPath()).thenReturn("/FhirStorm"); return req; } private ServletConfig createServletConfig() { ServletConfig sc = mock(ServletConfig.class); when(sc.getServletContext()).thenReturn(null); return sc; } private CapabilityStatementRestResourceComponent findRestResource(CapabilityStatement conformance, String wantResource) throws Exception { CapabilityStatementRestResourceComponent resource = null; for (CapabilityStatementRestResourceComponent 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 public void testConditionalOperations() throws Exception { RestfulServer rs = new RestfulServer(ourCtx); rs.setProviders(new ConditionalProvider()); ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs); rs.setServerConformanceProvider(sc); rs.init(createServletConfig()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); CapabilityStatementRestResourceComponent res = conformance.getRest().get(0).getResource().get(1); assertEquals("Patient", res.getType()); assertTrue(res.getConditionalCreate()); assertEquals(ConditionalDeleteStatus.MULTIPLE, res.getConditionalDelete()); assertTrue(res.getConditionalUpdate()); } @Test public void testExtendedOperationReturningBundle() throws Exception { RestfulServer rs = new RestfulServer(ourCtx); rs.setProviders(new ProviderWithExtendedOperationReturningBundle()); ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs); rs.setServerConformanceProvider(sc); rs.init(createServletConfig()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); assertEquals(1, conformance.getRest().get(0).getOperation().size()); assertEquals("everything", conformance.getRest().get(0).getOperation().get(0).getName()); OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-everything")); validate(opDef); assertEquals("everything", opDef.getCode()); } @Test public void testExtendedOperationReturningBundleOperation() throws Exception { RestfulServer rs = new RestfulServer(ourCtx); rs.setProviders(new ProviderWithExtendedOperationReturningBundle()); ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs) { }; rs.setServerConformanceProvider(sc); rs.init(createServletConfig()); OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-everything")); validate(opDef); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef); ourLog.info(conf); assertEquals("everything", opDef.getCode()); assertEquals(true, opDef.getIdempotent()); } @Test public void testInstanceHistorySupported() throws Exception { RestfulServer rs = new RestfulServer(ourCtx); rs.setProviders(new InstanceHistoryProvider()); ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs); rs.setServerConformanceProvider(sc); rs.init(createServletConfig()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); conf = ourCtx.newXmlParser().setPrettyPrint(false).encodeResourceToString(conformance); assertThat(conf, containsString("<interaction><code value=\"" + TypeRestfulInteraction.HISTORYINSTANCE.toCode() + "\"/></interaction>")); } @Test public void testMultiOptionalDocumentation() throws Exception { RestfulServer rs = new RestfulServer(ourCtx); rs.setProviders(new MultiOptionalProvider()); ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(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().iterator().next(); assertEquals("The patient's identifier", param.getDescription()); found = true; } } assertTrue(found); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); assertThat(conf, containsString("<documentation value=\"The patient's identifier\"/>")); assertThat(conf, containsString("<documentation value=\"The patient's name\"/>")); assertThat(conf, containsString("<type value=\"token\"/>")); } @Test public void testNonConditionalOperations() throws Exception { RestfulServer rs = new RestfulServer(ourCtx); rs.setProviders(new NonConditionalProvider()); ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs); rs.setServerConformanceProvider(sc); rs.init(createServletConfig()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); CapabilityStatementRestResourceComponent res = conformance.getRest().get(0).getResource().get(1); assertEquals("Patient", res.getType()); assertNull(res.getConditionalCreateElement().getValue()); assertNull(res.getConditionalDeleteElement().getValue()); assertNull(res.getConditionalUpdateElement().getValue()); } /** See #379 */ @Test public void testOperationAcrossMultipleTypes() throws Exception { RestfulServer rs = new RestfulServer(ourCtx); rs.setProviders(new MultiTypePatientProvider(), new MultiTypeEncounterProvider()); ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs); rs.setServerConformanceProvider(sc); rs.init(createServletConfig()); CapabilityStatement 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")); validate(opDef); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef)); Set<String> types = toStrings(opDef.getResource()); 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")); validate(opDef); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef)); Set<String> types = toStrings(opDef.getResource()); 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")); validate(opDef); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef)); Set<String> types = toStrings(opDef.getResource()); 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 public void testOperationDocumentation() throws Exception { RestfulServer rs = new RestfulServer(ourCtx); rs.setProviders(new SearchProvider()); ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs); rs.setServerConformanceProvider(sc); rs.init(createServletConfig()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); assertThat(conf, containsString("<documentation value=\"The patient's identifier (MRN or other card number)\"/>")); assertThat(conf, containsString("<type value=\"token\"/>")); } @Test public void testOperationOnNoTypes() throws Exception { RestfulServer rs = new RestfulServer(ourCtx); rs.setProviders(new PlainProviderWithExtendedOperationOnNoType()); ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs) { @Override public CapabilityStatement getServerConformance(HttpServletRequest theRequest) { return super.getServerConformance(theRequest); } }; rs.setServerConformanceProvider(sc); rs.init(createServletConfig()); OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/-is-plain")); validate(opDef); assertEquals("plain", opDef.getCode()); assertEquals(true, opDef.getIdempotent()); assertEquals(3, opDef.getParameter().size()); assertTrue(opDef.getParameter().get(0).hasName()); assertEquals("start", opDef.getParameter().get(0).getName()); assertEquals("in", opDef.getParameter().get(0).getUse().toCode()); assertEquals("0", opDef.getParameter().get(0).getMinElement().getValueAsString()); assertEquals("date", opDef.getParameter().get(0).getTypeElement().getValueAsString()); assertEquals("out1", opDef.getParameter().get(2).getName()); assertEquals("out", opDef.getParameter().get(2).getUse().toCode()); assertEquals("1", opDef.getParameter().get(2).getMinElement().getValueAsString()); assertEquals("2", opDef.getParameter().get(2).getMaxElement().getValueAsString()); assertEquals("string", opDef.getParameter().get(2).getTypeElement().getValueAsString()); } @Test public void testProviderWithRequiredAndOptional() throws Exception { RestfulServer rs = new RestfulServer(ourCtx); rs.setProviders(new ProviderWithRequiredAndOptional()); ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs); rs.setServerConformanceProvider(sc); rs.init(createServletConfig()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); CapabilityStatementRestComponent rest = conformance.getRest().get(0); CapabilityStatementRestResourceComponent res = rest.getResource().get(0); assertEquals("DiagnosticReport", res.getType()); assertEquals(DiagnosticReport.SP_SUBJECT, res.getSearchParam().get(0).getName()); // assertEquals("identifier", res.getSearchParam().get(0).getChain().get(0).getValue()); assertEquals(DiagnosticReport.SP_CODE, res.getSearchParam().get(1).getName()); assertEquals(DiagnosticReport.SP_DATE, res.getSearchParam().get(2).getName()); assertEquals(1, res.getSearchInclude().size()); assertEquals("DiagnosticReport.result", res.getSearchInclude().get(0).getValue()); } @Test public void testReadAndVReadSupported() throws Exception { RestfulServer rs = new RestfulServer(ourCtx); rs.setProviders(new VreadProvider()); ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs); rs.setServerConformanceProvider(sc); rs.init(createServletConfig()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); conf = ourCtx.newXmlParser().setPrettyPrint(false).encodeResourceToString(conformance); assertThat(conf, containsString("<interaction><code value=\"vread\"/></interaction>")); assertThat(conf, containsString("<interaction><code value=\"read\"/></interaction>")); } @Test public void testReadSupported() throws Exception { RestfulServer rs = new RestfulServer(ourCtx); rs.setProviders(new ReadProvider()); ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs); rs.setServerConformanceProvider(sc); rs.init(createServletConfig()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); conf = ourCtx.newXmlParser().setPrettyPrint(false).encodeResourceToString(conformance); assertThat(conf, not(containsString("<interaction><code value=\"vread\"/></interaction>"))); assertThat(conf, containsString("<interaction><code value=\"read\"/></interaction>")); } @Test public void testSearchParameterDocumentation() throws Exception { RestfulServer rs = new RestfulServer(ourCtx); rs.setProviders(new SearchProvider()); ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(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); for (IParameter next : binding.getParameters()) { SearchParameter param = (SearchParameter) next; if (param.getDescription().contains("The patient's identifier (MRN or other card number")) { found = true; } } found = true; } } assertTrue(found); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); assertThat(conf, containsString("<documentation value=\"The patient's identifier (MRN or other card number)\"/>")); assertThat(conf, containsString("<type value=\"token\"/>")); } /** * See #286 */ @Test public void testSearchReferenceParameterDocumentation() throws Exception { RestfulServer rs = new RestfulServer(ourCtx); rs.setProviders(new PatientResourceProvider()); ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(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); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); } /** * See #286 */ @Test public void testSearchReferenceParameterWithWhitelistDocumentation() throws Exception { RestfulServer rs = new RestfulServer(ourCtx); rs.setProviders(new SearchProviderWithWhitelist()); ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(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); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); CapabilityStatementRestResourceComponent resource = findRestResource(conformance, "Patient"); CapabilityStatementRestResourceSearchParamComponent 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 public void testSearchReferenceParameterWithList() throws Exception { RestfulServer rsNoType = new RestfulServer(ourCtx); rsNoType.registerProvider(new SearchProviderWithListNoType()); ServerCapabilityStatementProvider scNoType = new ServerCapabilityStatementProvider(rsNoType); rsNoType.setServerConformanceProvider(scNoType); rsNoType.init(createServletConfig()); scNoType.getServerConfiguration().setConformanceDate("2011-02-22T11:22:33Z"); CapabilityStatement conformance = scNoType.getServerConformance(createHttpServletRequest()); String confNoType = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(confNoType); RestfulServer rsWithType = new RestfulServer(ourCtx); rsWithType.registerProvider(new SearchProviderWithListWithType()); ServerCapabilityStatementProvider scWithType = new ServerCapabilityStatementProvider(rsWithType); rsWithType.setServerConformanceProvider(scWithType); rsWithType.init(createServletConfig()); scWithType.getServerConfiguration().setConformanceDate("2011-02-22T11:22:33Z"); CapabilityStatement conformanceWithType = scWithType.getServerConformance(createHttpServletRequest()); String confWithType = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformanceWithType); ourLog.info(confWithType); assertEquals(confNoType, confWithType); } @Test public void testSystemHistorySupported() throws Exception { RestfulServer rs = new RestfulServer(ourCtx); rs.setProviders(new SystemHistoryProvider()); ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs); rs.setServerConformanceProvider(sc); rs.init(createServletConfig()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); conf = ourCtx.newXmlParser().setPrettyPrint(false).encodeResourceToString(conformance); assertThat(conf, containsString("<interaction><code value=\"" + SystemRestfulInteraction.HISTORYSYSTEM.toCode() + "\"/></interaction>")); } @Test public void testTypeHistorySupported() throws Exception { RestfulServer rs = new RestfulServer(ourCtx); rs.setProviders(new TypeHistoryProvider()); ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs); rs.setServerConformanceProvider(sc); rs.init(createServletConfig()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); conf = ourCtx.newXmlParser().setPrettyPrint(false).encodeResourceToString(conformance); assertThat(conf, containsString("<interaction><code value=\"" + TypeRestfulInteraction.HISTORYTYPE.toCode() + "\"/></interaction>")); } @Test public void testValidateGeneratedStatement() throws Exception { RestfulServer rs = new RestfulServer(ourCtx); rs.setProviders(new MultiOptionalProvider()); ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs); rs.setServerConformanceProvider(sc); rs.init(createServletConfig()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance)); ValidationResult result = ourCtx.newValidator().validateWithResult(conformance); assertTrue(result.getMessages().toString(), result.isSuccessful()); } private List<String> toOperationIdParts(List<CapabilityStatementRestOperationComponent> theOperation) { ArrayList<String> retVal = Lists.newArrayList(); for (CapabilityStatementRestOperationComponent next : theOperation) { retVal.add(next.getDefinition().getReferenceElement().getIdPart()); } return retVal; } private List<String> toOperationNames(List<CapabilityStatementRestOperationComponent> theOperation) { ArrayList<String> retVal = Lists.newArrayList(); for (CapabilityStatementRestOperationComponent 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; } private void validate(OperationDefinition theOpDef) { String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(theOpDef); ourLog.info("Def: {}", conf); ValidationResult result = ourValidator.validateWithResult(theOpDef); String outcome = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result.toOperationOutcome()); ourLog.info("Outcome: {}", outcome); assertTrue(outcome, result.isSuccessful()); } @AfterClass public static void afterClassClearContext() { TestUtil.clearAllStaticFieldsForUnitTest(); } @SuppressWarnings("unused") public static class ConditionalProvider implements IResourceProvider { @Create public MethodOutcome create(@ResourceParam Patient thePatient, @ConditionalUrlParam String theConditionalUrl) { return null; } @Delete public MethodOutcome delete(@IdParam IdType theId, @ConditionalUrlParam(supportsMultiple = true) String theConditionalUrl) { return null; } @Override public Class<? extends IBaseResource> getResourceType() { return Patient.class; } @Update public MethodOutcome update(@IdParam IdType theId, @ResourceParam Patient thePatient, @ConditionalUrlParam String theConditionalUrl) { return null; } } @SuppressWarnings("unused") public static class InstanceHistoryProvider implements IResourceProvider { @Override public Class<? extends IBaseResource> getResourceType() { return Patient.class; } @History public List<IBaseResource> history(@IdParam IdType theId) { return null; } } @SuppressWarnings("unused") public static class MultiOptionalProvider { @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) { return null; } } @SuppressWarnings("unused") 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; } } @SuppressWarnings("unused") 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; } } @SuppressWarnings("unused") public static class NonConditionalProvider implements IResourceProvider { @Create public MethodOutcome create(@ResourceParam Patient thePatient) { return null; } @Delete public MethodOutcome delete(@IdParam IdType theId) { return null; } @Override public Class<? extends IBaseResource> getResourceType() { return Patient.class; } @Update public MethodOutcome update(@IdParam IdType theId, @ResourceParam Patient thePatient) { return null; } } @SuppressWarnings("unused") public static class PlainProviderWithExtendedOperationOnNoType { @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) { return null; } } @SuppressWarnings("unused") public static class ProviderWithExtendedOperationReturningBundle implements IResourceProvider { @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) { return null; } @Override public Class<? extends IBaseResource> getResourceType() { return Patient.class; } } @SuppressWarnings("unused") public static class ProviderWithRequiredAndOptional { @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 { return null; } } @SuppressWarnings("unused") public static class ReadProvider { @Search(type = Patient.class) public Patient findPatient(@Description(shortDefinition = "The patient's identifier (MRN or other card number)") @RequiredParam(name = Patient.SP_IDENTIFIER) TokenParam theIdentifier) { return null; } @Read(version = false) public Patient readPatient(@IdParam IdType theId) { return null; } } @SuppressWarnings("unused") public static class SearchProvider { @Search(type = Patient.class) public Patient findPatient1(@Description(shortDefinition = "The patient's identifier (MRN or other card number)") @RequiredParam(name = Patient.SP_IDENTIFIER) TokenParam theIdentifier) { return null; } @Search(type = Patient.class) public Patient findPatient2( @Description(shortDefinition = "All patients linked to the given patient") @OptionalParam(name = "link", targetTypes = { Patient.class }) ReferenceAndListParam theLink) { return null; } } @SuppressWarnings("unused") 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) { return null; } } @SuppressWarnings("unused") public static class SearchProviderWithListNoType implements IResourceProvider { @Override public Class<? extends IBaseResource> getResourceType() { return Patient.class; } @Search() public List<Patient> findPatient1(@Description(shortDefinition = "The organization at which this person is a patient") @RequiredParam(name = Patient.SP_ORGANIZATION) ReferenceAndListParam theIdentifier) { return null; } } @SuppressWarnings("unused") public static class SearchProviderWithListWithType implements IResourceProvider { @Override public Class<? extends IBaseResource> getResourceType() { return 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; } } public static class SystemHistoryProvider { @History public List<IBaseResource> history() { return null; } } public static class TypeHistoryProvider implements IResourceProvider { @Override public Class<? extends IBaseResource> getResourceType() { return Patient.class; } @History public List<IBaseResource> history() { return null; } } @SuppressWarnings("unused") public static class VreadProvider { @Search(type = Patient.class) public Patient findPatient(@Description(shortDefinition = "The patient's identifier (MRN or other card number)") @RequiredParam(name = Patient.SP_IDENTIFIER) TokenParam theIdentifier) { return null; } @Read(version = true) public Patient readPatient(@IdParam IdType theId) { return null; } } }