-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow custom operations/providers in addition to interceptors (#654)
* Allow custom operations/providers to be added in the same way custom interceptors are currently loaded * Add new property to documentation and default yaml file * Add test for custom operation
- Loading branch information
Showing
7 changed files
with
193 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
src/test/java/ca/uhn/fhir/jpa/starter/CustomOperationTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package ca.uhn.fhir.jpa.starter; | ||
|
||
import ca.uhn.fhir.context.FhirContext; | ||
import ca.uhn.fhir.rest.api.MethodOutcome; | ||
import ca.uhn.fhir.rest.client.api.IGenericClient; | ||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; | ||
import org.hl7.fhir.r4.model.Binary; | ||
import org.hl7.fhir.r4.model.Parameters; | ||
import org.junit.jupiter.api.Assertions; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.boot.test.web.server.LocalServerPort; | ||
|
||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = {Application.class}, properties = { | ||
"hapi.fhir.custom-bean-packages=some.custom.pkg1", | ||
"hapi.fhir.custom-provider-classes=some.custom.pkg1.CustomOperationBean,some.custom.pkg1.CustomOperationPojo", | ||
"spring.datasource.url=jdbc:h2:mem:dbr4", | ||
"hapi.fhir.cr_enabled=false", | ||
// "hapi.fhir.enable_repository_validating_interceptor=true", | ||
"hapi.fhir.fhir_version=r4" | ||
}) | ||
|
||
class CustomOperationTest { | ||
|
||
@LocalServerPort | ||
private int port; | ||
|
||
private IGenericClient client; | ||
private FhirContext ctx; | ||
|
||
@BeforeEach | ||
void setUp() { | ||
ctx = FhirContext.forR4(); | ||
ctx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); | ||
ctx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); | ||
String ourServerBase = "http://localhost:" + port + "/fhir/"; | ||
client = ctx.newRestfulGenericClient(ourServerBase); | ||
|
||
// Properties props = new Properties(); | ||
// props.put("spring.autoconfigure.exclude", "org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration"); | ||
} | ||
|
||
@Test | ||
void testCustomOperations() { | ||
|
||
// we registered two custom operations via the property 'hapi.fhir.custom-provider-classes' | ||
// one is discovered as a Spring Bean ($springBeanOperation), one instantiated via reflection ($pojoOperation) | ||
// both should be registered with the server and will add a custom operation. | ||
|
||
// test Spring bean operation | ||
MethodOutcome springBeanOutcome = client.operation().onServer().named("$springBeanOperation") | ||
.withNoParameters(Parameters.class).returnMethodOutcome().execute(); | ||
|
||
// the hapi client will return our operation result (just a string) as a Binary with the string stored as the | ||
// data | ||
Assertions.assertEquals(200, springBeanOutcome.getResponseStatusCode()); | ||
Binary springReturnResource = (Binary) springBeanOutcome.getResource(); | ||
String springReturn = new String(springReturnResource.getData()); | ||
Assertions.assertEquals("springBean", springReturn); | ||
|
||
// test Pojo bean | ||
MethodOutcome pojoOutcome = client.operation().onServer().named("$pojoOperation") | ||
.withNoParameters(Parameters.class).returnMethodOutcome().execute(); | ||
|
||
Assertions.assertEquals(200, pojoOutcome.getResponseStatusCode()); | ||
Binary pojoReturnResource = (Binary) pojoOutcome.getResource(); | ||
String pojoReturn = new String(pojoReturnResource.getData()); | ||
Assertions.assertEquals("pojo", pojoReturn); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package some.custom.pkg1; | ||
|
||
import ca.uhn.fhir.rest.annotation.Operation; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
import org.apache.commons.io.IOUtils; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.io.IOException; | ||
|
||
/** | ||
* Code taken from hapi documentation on how to implement an operation which handles its own request/response | ||
* <a href="https://hapifhir.io/hapi-fhir/docs/server_plain/rest_operations_operations.html#manually-handing-requestresponse">...</a> | ||
*/ | ||
|
||
@Component | ||
public class CustomOperationBean { | ||
|
||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CustomOperationBean.class); | ||
|
||
@Operation(name = "$springBeanOperation", manualResponse = true, manualRequest = true) | ||
public void springBeanOperation(HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) | ||
throws IOException { | ||
String contentType = theServletRequest.getContentType(); | ||
byte[] bytes = IOUtils.toByteArray(theServletRequest.getInputStream()); | ||
|
||
ourLog.info("Received call with content type {} and {} bytes", contentType, bytes.length); | ||
|
||
theServletResponse.setContentType("text/plain"); | ||
theServletResponse.getWriter().write("springBean"); | ||
theServletResponse.getWriter().close(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package some.custom.pkg1; | ||
|
||
import ca.uhn.fhir.rest.annotation.Operation; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
import org.apache.commons.io.IOUtils; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.io.IOException; | ||
|
||
public class CustomOperationPojo { | ||
|
||
private final Logger LOGGER = LoggerFactory.getLogger(CustomOperationPojo.class); | ||
|
||
@Operation(name = "$pojoOperation", manualResponse = true, manualRequest = true) | ||
public void $pojoOperation(HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) | ||
throws IOException { | ||
String contentType = theServletRequest.getContentType(); | ||
byte[] bytes = IOUtils.toByteArray(theServletRequest.getInputStream()); | ||
|
||
LOGGER.info("Received call with content type {} and {} bytes", contentType, bytes.length); | ||
|
||
theServletResponse.setContentType("text/plain"); | ||
theServletResponse.getWriter().write("pojo"); | ||
theServletResponse.getWriter().close(); | ||
} | ||
} |