Fix #267
This commit is contained in:
parent
6c9707b86e
commit
189038ad08
|
@ -355,13 +355,13 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
||||||
} else if (theValue.charAt(0) == 'Z') {
|
} else if (theValue.charAt(0) == 'Z') {
|
||||||
clearTimeZone();
|
clearTimeZone();
|
||||||
setTimeZoneZulu(true);
|
setTimeZoneZulu(true);
|
||||||
} else if (theValue.length() != 5) {
|
} else if (theValue.length() != 6) {
|
||||||
throwBadDateFormat(theWholeValue, "Timezone offset must be in the form \"Z\", \"-HH:mm\", or \"+HH:mm\"");
|
throwBadDateFormat(theWholeValue, "Timezone offset must be in the form \"Z\", \"-HH:mm\", or \"+HH:mm\"");
|
||||||
} else if (theValue.charAt(3) != ':' || !(theValue.charAt(0) == '+' || theValue.charAt(0) == '-')) {
|
} else if (theValue.charAt(3) != ':' || !(theValue.charAt(0) == '+' || theValue.charAt(0) == '-')) {
|
||||||
throwBadDateFormat(theWholeValue, "Timezone offset must be in the form \"Z\", \"-HH:mm\", or \"+HH:mm\"");
|
throwBadDateFormat(theWholeValue, "Timezone offset must be in the form \"Z\", \"-HH:mm\", or \"+HH:mm\"");
|
||||||
} else {
|
} else {
|
||||||
parseInt(theWholeValue, theValue.substring(0, 2), 0, 23);
|
parseInt(theWholeValue, theValue.substring(1, 3), 0, 23);
|
||||||
parseInt(theWholeValue, theValue.substring(3, 5), 0, 59);
|
parseInt(theWholeValue, theValue.substring(4, 6), 0, 59);
|
||||||
clearTimeZone();
|
clearTimeZone();
|
||||||
setTimeZone(TimeZone.getTimeZone("GMT" + theValue));
|
setTimeZone(TimeZone.getTimeZone("GMT" + theValue));
|
||||||
}
|
}
|
||||||
|
|
|
@ -265,7 +265,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(methodBinding.getName()).getDefinition().setReference("OperationDefinition/" + opName);
|
rest.addOperation().setName(opName).getDefinition().setReference("OperationDefinition/" + opName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ import ca.uhn.fhir.rest.annotation.Operation;
|
||||||
import ca.uhn.fhir.rest.annotation.OperationParam;
|
import ca.uhn.fhir.rest.annotation.OperationParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Read;
|
import ca.uhn.fhir.rest.annotation.Read;
|
||||||
import ca.uhn.fhir.rest.client.IGenericClient;
|
import ca.uhn.fhir.rest.client.IGenericClient;
|
||||||
|
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||||
import ca.uhn.fhir.util.PortUtil;
|
import ca.uhn.fhir.util.PortUtil;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
|
||||||
|
@ -76,23 +77,39 @@ public class OperationServerDstu2Test {
|
||||||
ourLastMethod = "";
|
ourLastMethod = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConformance() throws Exception {
|
public void testConformance() throws Exception {
|
||||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort);
|
IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort);
|
||||||
Conformance p = client.fetchConformance().ofType(Conformance.class).execute();
|
LoggingInterceptor loggingInterceptor = new LoggingInterceptor();
|
||||||
|
loggingInterceptor.setLogResponseBody(true);
|
||||||
|
client.registerInterceptor(loggingInterceptor);
|
||||||
|
|
||||||
|
Conformance p = client.fetchConformance().ofType(Conformance.class).prettyPrint().execute();
|
||||||
List<RestOperation> ops = p.getRest().get(0).getOperation();
|
List<RestOperation> ops = p.getRest().get(0).getOperation();
|
||||||
assertThat(ops.size(), greaterThan(1));
|
assertThat(ops.size(), greaterThan(1));
|
||||||
assertNull(ops.get(0).getDefinition().getReference().getBaseUrl());
|
assertNull(ops.get(0).getDefinition().getReference().getBaseUrl());
|
||||||
assertThat(ops.get(0).getDefinition().getReference().getValue(), startsWith("OperationDefinition/"));
|
assertThat(ops.get(0).getDefinition().getReference().getValue(), startsWith("OperationDefinition/"));
|
||||||
|
|
||||||
OperationDefinition def = client.read().resource(OperationDefinition.class).withId(ops.get(0).getDefinition().getReference()).execute();
|
OperationDefinition def = client.read().resource(OperationDefinition.class).withId(ops.get(0).getDefinition().getReference()).execute();
|
||||||
assertThat(def.getCode(), not(blankOrNullString()));
|
assertThat(def.getCode(), not(blankOrNullString()));
|
||||||
|
|
||||||
|
List<String> opNames = toOpNames(ops);
|
||||||
|
assertThat(opNames, containsInRelativeOrder("OP_TYPE"));
|
||||||
|
|
||||||
|
assertEquals("OperationDefinition/OP_TYPE", ops.get(opNames.indexOf("OP_TYPE")).getDefinition().getReference().getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> toOpNames(List<RestOperation> theOps) {
|
||||||
|
ArrayList<String> retVal = new ArrayList<String>();
|
||||||
|
for (RestOperation next : theOps) {
|
||||||
|
retVal.add(next.getName());
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInstanceEverythingGet() throws Exception {
|
public void testInstanceEverythingGet() throws Exception {
|
||||||
|
|
||||||
// Try with a GET
|
// Try with a GET
|
||||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$everything");
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$everything");
|
||||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||||
|
@ -104,9 +121,9 @@ public class OperationServerDstu2Test {
|
||||||
assertEquals("instance $everything", ourLastMethod);
|
assertEquals("instance $everything", ourLastMethod);
|
||||||
assertThat(response, startsWith("<Bundle"));
|
assertThat(response, startsWith("<Bundle"));
|
||||||
assertEquals("Patient/123", ourLastId.toUnqualifiedVersionless().getValue());
|
assertEquals("Patient/123", ourLastId.toUnqualifiedVersionless().getValue());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInstanceEverythingHapiClient() throws Exception {
|
public void testInstanceEverythingHapiClient() throws Exception {
|
||||||
Parameters p = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort).operation().onInstance(new IdDt("Patient/123")).named("$everything").withParameters(new Parameters()).execute();
|
Parameters p = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort).operation().onInstance(new IdDt("Patient/123")).named("$everything").withParameters(new Parameters()).execute();
|
||||||
|
@ -115,13 +132,12 @@ public class OperationServerDstu2Test {
|
||||||
assertEquals("instance $everything", ourLastMethod);
|
assertEquals("instance $everything", ourLastMethod);
|
||||||
assertEquals("Patient/123", ourLastId.toUnqualifiedVersionless().getValue());
|
assertEquals("Patient/123", ourLastId.toUnqualifiedVersionless().getValue());
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInstanceEverythingPost() throws Exception {
|
public void testInstanceEverythingPost() throws Exception {
|
||||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(new Parameters());
|
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(new Parameters());
|
||||||
|
|
||||||
// Try with a POST
|
// Try with a POST
|
||||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/123/$everything");
|
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/123/$everything");
|
||||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||||
|
@ -167,7 +183,7 @@ public class OperationServerDstu2Test {
|
||||||
IOUtils.closeQuietly(status);
|
IOUtils.closeQuietly(status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOperationOnInstance() throws Exception {
|
public void testOperationOnInstance() throws Exception {
|
||||||
Parameters p = new Parameters();
|
Parameters p = new Parameters();
|
||||||
|
@ -190,11 +206,11 @@ public class OperationServerDstu2Test {
|
||||||
|
|
||||||
Parameters resp = ourCtx.newXmlParser().parseResource(Parameters.class, response);
|
Parameters resp = ourCtx.newXmlParser().parseResource(Parameters.class, response);
|
||||||
assertEquals("RET1", resp.getParameter().get(0).getName());
|
assertEquals("RET1", resp.getParameter().get(0).getName());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Against type should fail
|
* Against type should fail
|
||||||
*/
|
*/
|
||||||
|
|
||||||
httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$OP_INSTANCE");
|
httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$OP_INSTANCE");
|
||||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||||
status = ourClient.execute(httpPost);
|
status = ourClient.execute(httpPost);
|
||||||
|
@ -228,7 +244,7 @@ public class OperationServerDstu2Test {
|
||||||
|
|
||||||
Parameters resp = ourCtx.newXmlParser().parseResource(Parameters.class, response);
|
Parameters resp = ourCtx.newXmlParser().parseResource(Parameters.class, response);
|
||||||
assertEquals("RET1", resp.getParameter().get(0).getName());
|
assertEquals("RET1", resp.getParameter().get(0).getName());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -237,7 +253,7 @@ public class OperationServerDstu2Test {
|
||||||
p.addParameter().setName("PARAM1").setValue(new StringDt("PARAM1val"));
|
p.addParameter().setName("PARAM1").setValue(new StringDt("PARAM1val"));
|
||||||
p.addParameter().setName("PARAM2").setResource(new Patient().setActive(true));
|
p.addParameter().setName("PARAM2").setResource(new Patient().setActive(true));
|
||||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||||
|
|
||||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$OP_INSTANCE_OR_TYPE");
|
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$OP_INSTANCE_OR_TYPE");
|
||||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||||
CloseableHttpResponse status = ourClient.execute(httpPost);
|
CloseableHttpResponse status = ourClient.execute(httpPost);
|
||||||
|
@ -333,7 +349,7 @@ public class OperationServerDstu2Test {
|
||||||
String response = IOUtils.toString(status.getEntity().getContent());
|
String response = IOUtils.toString(status.getEntity().getContent());
|
||||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
ourLog.info(response);
|
ourLog.info(response);
|
||||||
|
|
||||||
Bundle resp = ourCtx.newXmlParser().parseResource(Bundle.class, response);
|
Bundle resp = ourCtx.newXmlParser().parseResource(Bundle.class, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,7 +369,7 @@ public class OperationServerDstu2Test {
|
||||||
Parameters resp = ourCtx.newXmlParser().parseResource(Parameters.class, response);
|
Parameters resp = ourCtx.newXmlParser().parseResource(Parameters.class, response);
|
||||||
assertEquals("RET1", resp.getParameter().get(0).getName());
|
assertEquals("RET1", resp.getParameter().get(0).getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOperationWithGetUsingParamsFailsWithNonPrimitive() throws Exception {
|
public void testOperationWithGetUsingParamsFailsWithNonPrimitive() throws Exception {
|
||||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$OP_TYPE?PARAM1=PARAM1val&PARAM2=foo");
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$OP_TYPE?PARAM1=PARAM1val&PARAM2=foo");
|
||||||
|
@ -367,7 +383,6 @@ public class OperationServerDstu2Test {
|
||||||
assertThat(response, containsString("Can not invoke operation $OP_TYPE using HTTP GET because parameter PARAM2 is not a primitive datatype"));
|
assertThat(response, containsString("Can not invoke operation $OP_TYPE using HTTP GET because parameter PARAM2 is not a primitive datatype"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOperationWithListParam() throws Exception {
|
public void testOperationWithListParam() throws Exception {
|
||||||
Parameters p = new Parameters();
|
Parameters p = new Parameters();
|
||||||
|
@ -479,7 +494,6 @@ public class OperationServerDstu2Test {
|
||||||
assertEquals("read", ourLastMethod);
|
assertEquals("read", ourLastMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
public static void afterClassClearContext() throws Exception {
|
public static void afterClassClearContext() throws Exception {
|
||||||
ourServer.stop();
|
ourServer.stop();
|
||||||
|
@ -494,9 +508,9 @@ public class OperationServerDstu2Test {
|
||||||
|
|
||||||
ServletHandler proxyHandler = new ServletHandler();
|
ServletHandler proxyHandler = new ServletHandler();
|
||||||
RestfulServer servlet = new RestfulServer(ourCtx);
|
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||||
|
|
||||||
servlet.setPagingProvider(new FifoMemoryPagingProvider(10).setDefaultPageSize(2));
|
servlet.setPagingProvider(new FifoMemoryPagingProvider(10).setDefaultPageSize(2));
|
||||||
|
|
||||||
servlet.setFhirContext(ourCtx);
|
servlet.setFhirContext(ourCtx);
|
||||||
servlet.setResourceProviders(new PatientProvider());
|
servlet.setResourceProviders(new PatientProvider());
|
||||||
servlet.setPlainProviders(new PlainProvider());
|
servlet.setPlainProviders(new PlainProvider());
|
||||||
|
@ -644,7 +658,7 @@ public class OperationServerDstu2Test {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(name = "$everything", idempotent=true)
|
@Operation(name = "$everything", idempotent = true)
|
||||||
public Bundle patientEverything(@IdParam IdDt thePatientId) {
|
public Bundle patientEverything(@IdParam IdDt thePatientId) {
|
||||||
ourLastMethod = "instance $everything";
|
ourLastMethod = "instance $everything";
|
||||||
ourLastId = thePatientId;
|
ourLastId = thePatientId;
|
||||||
|
|
|
@ -88,21 +88,28 @@ import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
* Server FHIR Provider which serves the conformance statement for a RESTful server implementation
|
* Server FHIR Provider which serves the conformance statement for a RESTful server implementation
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* Note: This class is safe to extend, but it is important to note that the same instance of {@link Conformance} is
|
* Note: This class is safe to extend, but it is important to note that the same instance of {@link Conformance} is always returned unless {@link #setCache(boolean)} is called with a value of
|
||||||
* always returned unless {@link #setCache(boolean)} is called with a value of <code>false</code>. This means that if
|
* <code>false</code>. This means that if you are adding anything to the returned conformance instance on each call you should call <code>setCache(false)</code> in your provider constructor.
|
||||||
* you are adding anything to the returned conformance instance on each call you should call
|
|
||||||
* <code>setCache(false)</code> in your provider constructor.
|
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public class ServerConformanceProvider implements IServerConformanceProvider<Conformance> {
|
public class ServerConformanceProvider implements IServerConformanceProvider<Conformance> {
|
||||||
|
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerConformanceProvider.class);
|
||||||
private boolean myCache = true;
|
private boolean myCache = true;
|
||||||
private volatile Conformance myConformance;
|
private volatile Conformance myConformance;
|
||||||
private IdentityHashMap<OperationMethodBinding, String> myOperationBindingToName;
|
private IdentityHashMap<OperationMethodBinding, String> myOperationBindingToName;
|
||||||
private HashMap<String, List<OperationMethodBinding>> myOperationNameToBindings;
|
private HashMap<String, List<OperationMethodBinding>> myOperationNameToBindings;
|
||||||
private String myPublisher = "Not provided";
|
private String myPublisher = "Not provided";
|
||||||
|
|
||||||
private RestulfulServerConfiguration myServerConfiguration;
|
private RestulfulServerConfiguration myServerConfiguration;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a no-arg constructor and seetter so that the ServerConfirmanceProvider can be Spring-wired with the RestfulService avoiding the potential reference cycle that would happen.
|
||||||
|
*/
|
||||||
|
public ServerConformanceProvider() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
public ServerConformanceProvider(RestfulServer theRestfulServer) {
|
public ServerConformanceProvider(RestfulServer theRestfulServer) {
|
||||||
this.myServerConfiguration = theRestfulServer.createConfiguration();
|
this.myServerConfiguration = theRestfulServer.createConfiguration();
|
||||||
}
|
}
|
||||||
|
@ -111,18 +118,6 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
this.myServerConfiguration = theServerConfiguration;
|
this.myServerConfiguration = theServerConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Add a no-arg constructor and seetter so that the ServerConfirmanceProvider can be Spring-wired with the
|
|
||||||
* RestfulService avoiding the potential reference cycle that would happen.
|
|
||||||
*/
|
|
||||||
public ServerConformanceProvider() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRestfulServer(RestfulServer theRestfulServer) {
|
|
||||||
myServerConfiguration = theRestfulServer.createConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkBindingForSystemOps(ConformanceRestComponent rest, Set<SystemRestfulInteraction> systemOps, BaseMethodBinding<?> nextMethodBinding) {
|
private void checkBindingForSystemOps(ConformanceRestComponent rest, Set<SystemRestfulInteraction> systemOps, BaseMethodBinding<?> nextMethodBinding) {
|
||||||
if (nextMethodBinding.getRestOperationType() != null) {
|
if (nextMethodBinding.getRestOperationType() != null) {
|
||||||
String sysOpCode = nextMethodBinding.getRestOperationType().getCode();
|
String sysOpCode = nextMethodBinding.getRestOperationType().getCode();
|
||||||
|
@ -165,14 +160,25 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
return resourceToMethods;
|
return resourceToMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DateTimeType conformanceDate() {
|
||||||
|
String buildDate = myServerConfiguration.getConformanceDate();
|
||||||
|
if (buildDate != null) {
|
||||||
|
try {
|
||||||
|
return new DateTimeType(buildDate);
|
||||||
|
} catch (DataFormatException e) {
|
||||||
|
// fall through
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DateTimeType.now();
|
||||||
|
}
|
||||||
|
|
||||||
private String createOperationName(OperationMethodBinding theMethodBinding) {
|
private String createOperationName(OperationMethodBinding theMethodBinding) {
|
||||||
return theMethodBinding.getName().substring(1);
|
return theMethodBinding.getName().substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value of the "publisher" that will be placed in the generated conformance statement. As this is a
|
* Gets the value of the "publisher" that will be placed in the generated conformance statement. As this is a mandatory element, the value should not be null (although this is not enforced). The
|
||||||
* mandatory element, the value should not be null (although this is not enforced). The value defaults to
|
* value defaults to "Not provided" but may be set to null, which will cause this element to be omitted.
|
||||||
* "Not provided" but may be set to null, which will cause this element to be omitted.
|
|
||||||
*/
|
*/
|
||||||
public String getPublisher() {
|
public String getPublisher() {
|
||||||
return myPublisher;
|
return myPublisher;
|
||||||
|
@ -283,7 +289,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(methodBinding.getName()).setDefinition(new Reference(readOperationDefinition(new IdType(opName))));
|
rest.addOperation().setName(opName).setDefinition(new Reference(readOperationDefinition(new IdType(opName))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +323,8 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
|
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
|
||||||
String opName = myOperationBindingToName.get(methodBinding);
|
String opName = myOperationBindingToName.get(methodBinding);
|
||||||
if (operationNames.add(opName)) {
|
if (operationNames.add(opName)) {
|
||||||
rest.addOperation().setName(methodBinding.getName()).setDefinition(new Reference(readOperationDefinition(new IdType(opName))));
|
ourLog.info("Found bound operation: {}", opName);
|
||||||
|
rest.addOperation().setName(opName).setDefinition(new Reference(readOperationDefinition(new IdType(opName))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -328,18 +335,6 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DateTimeType conformanceDate() {
|
|
||||||
String buildDate = myServerConfiguration.getConformanceDate();
|
|
||||||
if (buildDate != null) {
|
|
||||||
try {
|
|
||||||
return new DateTimeType(buildDate);
|
|
||||||
} catch (DataFormatException e) {
|
|
||||||
// fall through
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return DateTimeType.now();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleDynamicSearchMethodBinding(ConformanceRestResourceComponent resource, RuntimeResourceDefinition def, TreeSet<String> includes, DynamicSearchMethodBinding searchMethodBinding) {
|
private void handleDynamicSearchMethodBinding(ConformanceRestResourceComponent resource, RuntimeResourceDefinition def, TreeSet<String> includes, DynamicSearchMethodBinding searchMethodBinding) {
|
||||||
includes.addAll(searchMethodBinding.getIncludes());
|
includes.addAll(searchMethodBinding.getIncludes());
|
||||||
|
|
||||||
|
@ -384,7 +379,8 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleSearchMethodBinding(ConformanceRestComponent rest, ConformanceRestResourceComponent resource, String resourceName, RuntimeResourceDefinition def, TreeSet<String> includes, SearchMethodBinding searchMethodBinding) {
|
private void handleSearchMethodBinding(ConformanceRestComponent rest, ConformanceRestResourceComponent resource, String resourceName, RuntimeResourceDefinition def, TreeSet<String> includes,
|
||||||
|
SearchMethodBinding searchMethodBinding) {
|
||||||
includes.addAll(searchMethodBinding.getIncludes());
|
includes.addAll(searchMethodBinding.getIncludes());
|
||||||
|
|
||||||
List<IParameter> params = searchMethodBinding.getParameters();
|
List<IParameter> params = searchMethodBinding.getParameters();
|
||||||
|
@ -438,7 +434,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
if (StringUtils.isNotBlank(chain)) {
|
if (StringUtils.isNotBlank(chain)) {
|
||||||
param.addChain(chain);
|
param.addChain(chain);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextParameter.getParamType() == RestSearchParameterTypeEnum.REFERENCE) {
|
if (nextParameter.getParamType() == RestSearchParameterTypeEnum.REFERENCE) {
|
||||||
for (String nextWhitelist : new TreeSet<String>(nextParameter.getQualifierWhitelist())) {
|
for (String nextWhitelist : new TreeSet<String>(nextParameter.getQualifierWhitelist())) {
|
||||||
if (nextWhitelist.startsWith(".")) {
|
if (nextWhitelist.startsWith(".")) {
|
||||||
|
@ -446,7 +442,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
param.setDocumentation(nextParamDescription);
|
param.setDocumentation(nextParamDescription);
|
||||||
if (nextParameter.getParamType() != null) {
|
if (nextParameter.getParamType() != null) {
|
||||||
param.getTypeElement().setValueAsString(nextParameter.getParamType().getCode());
|
param.getTypeElement().setValueAsString(nextParameter.getParamType().getCode());
|
||||||
|
@ -485,6 +481,8 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
}
|
}
|
||||||
|
|
||||||
String name = createOperationName(methodBinding);
|
String name = createOperationName(methodBinding);
|
||||||
|
ourLog.info("Detected operation: {}", name);
|
||||||
|
|
||||||
myOperationBindingToName.put(methodBinding, name);
|
myOperationBindingToName.put(methodBinding, name);
|
||||||
if (myOperationNameToBindings.containsKey(name) == false) {
|
if (myOperationNameToBindings.containsKey(name) == false) {
|
||||||
myOperationNameToBindings.put(name, new ArrayList<OperationMethodBinding>());
|
myOperationNameToBindings.put(name, new ArrayList<OperationMethodBinding>());
|
||||||
|
@ -519,7 +517,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(createOperationName(sharedDescription));
|
||||||
if (sharedDescription.isCanOperateAtInstanceLevel()) {
|
if (sharedDescription.isCanOperateAtInstanceLevel()) {
|
||||||
op.setInstance(sharedDescription.isCanOperateAtInstanceLevel());
|
op.setInstance(sharedDescription.isCanOperateAtInstanceLevel());
|
||||||
}
|
}
|
||||||
|
@ -579,14 +577,17 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the value of the "publisher" that will be placed in the generated conformance statement. As this is a
|
* Sets the value of the "publisher" that will be placed in the generated conformance statement. As this is a mandatory element, the value should not be null (although this is not enforced). The
|
||||||
* mandatory element, the value should not be null (although this is not enforced). The value defaults to
|
* value defaults to "Not provided" but may be set to null, which will cause this element to be omitted.
|
||||||
* "Not provided" but may be set to null, which will cause this element to be omitted.
|
|
||||||
*/
|
*/
|
||||||
public void setPublisher(String thePublisher) {
|
public void setPublisher(String thePublisher) {
|
||||||
myPublisher = thePublisher;
|
myPublisher = thePublisher;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setRestfulServer(RestfulServer theRestfulServer) {
|
||||||
|
myServerConfiguration = theRestfulServer.createConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
private void sortRuntimeSearchParameters(List<RuntimeSearchParam> searchParameters) {
|
private void sortRuntimeSearchParameters(List<RuntimeSearchParam> searchParameters) {
|
||||||
Collections.sort(searchParameters, new Comparator<RuntimeSearchParam>() {
|
Collections.sort(searchParameters, new Comparator<RuntimeSearchParam>() {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package ca.uhn.fhir.rest.server;
|
package ca.uhn.fhir.rest.server;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.blankOrNullString;
|
import static org.hamcrest.Matchers.blankOrNullString;
|
||||||
|
import static org.hamcrest.Matchers.containsInRelativeOrder;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.greaterThan;
|
import static org.hamcrest.Matchers.greaterThan;
|
||||||
import static org.hamcrest.Matchers.not;
|
import static org.hamcrest.Matchers.not;
|
||||||
|
@ -45,12 +46,12 @@ import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.model.api.IResource;
|
|
||||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Operation;
|
import ca.uhn.fhir.rest.annotation.Operation;
|
||||||
import ca.uhn.fhir.rest.annotation.OperationParam;
|
import ca.uhn.fhir.rest.annotation.OperationParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Read;
|
import ca.uhn.fhir.rest.annotation.Read;
|
||||||
import ca.uhn.fhir.rest.client.IGenericClient;
|
import ca.uhn.fhir.rest.client.IGenericClient;
|
||||||
|
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||||
import ca.uhn.fhir.util.PortUtil;
|
import ca.uhn.fhir.util.PortUtil;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
|
||||||
|
@ -84,10 +85,27 @@ public class OperationServerDstu3Test {
|
||||||
@Test
|
@Test
|
||||||
public void testConformance() throws Exception {
|
public void testConformance() throws Exception {
|
||||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort);
|
IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort);
|
||||||
Conformance p = client.fetchConformance().ofType(Conformance.class).execute();
|
LoggingInterceptor loggingInterceptor = new LoggingInterceptor();
|
||||||
|
loggingInterceptor.setLogResponseBody(true);
|
||||||
|
client.registerInterceptor(loggingInterceptor);
|
||||||
|
|
||||||
|
Conformance p = client.fetchConformance().ofType(Conformance.class).prettyPrint().execute();
|
||||||
List<ConformanceRestOperationComponent> ops = p.getRest().get(0).getOperation();
|
List<ConformanceRestOperationComponent> ops = p.getRest().get(0).getOperation();
|
||||||
assertThat(ops.size(), greaterThan(1));
|
assertThat(ops.size(), greaterThan(1));
|
||||||
assertThat(ops.get(0).getDefinition().getReferenceElement().getValue(), startsWith("#"));
|
|
||||||
|
List<String> opNames = toOpNames(ops);
|
||||||
|
assertThat(opNames, containsInRelativeOrder("OP_TYPE"));
|
||||||
|
|
||||||
|
OperationDefinition def = (OperationDefinition) ops.get(opNames.indexOf("OP_TYPE")).getDefinition().getResource();
|
||||||
|
assertEquals("OP_TYPE", def.getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> toOpNames(List<ConformanceRestOperationComponent> theOps) {
|
||||||
|
ArrayList<String> retVal = new ArrayList<String>();
|
||||||
|
for (ConformanceRestOperationComponent next : theOps) {
|
||||||
|
retVal.add(next.getName());
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -319,6 +319,11 @@
|
||||||
<![CDATA[<code>_raw=true</code>]]> mode has been deprecated and
|
<![CDATA[<code>_raw=true</code>]]> mode has been deprecated and
|
||||||
will be removed at some point.
|
will be removed at some point.
|
||||||
</action>
|
</action>
|
||||||
|
<action type="fix" issue="267">
|
||||||
|
Operation definitions (e.g. for $everything operation) in the generated
|
||||||
|
server conformance statement should not include the $ prefix in the operation
|
||||||
|
name or code. Thanks to Dion McMurtrie 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