Add interceptor for syntax highlighting

This commit is contained in:
James Agnew 2015-05-15 18:59:54 -04:00
parent 7517709edb
commit 0f9d4b8059
12 changed files with 82 additions and 25 deletions

View File

@ -7,6 +7,7 @@ import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.interceptor.ExceptionHandlingInterceptor; import ca.uhn.fhir.rest.server.interceptor.ExceptionHandlingInterceptor;
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor; import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class ServletExamples { public class ServletExamples {
@ -47,7 +48,7 @@ public class ServletExamples {
// ... define your resource providers here ... // ... define your resource providers here ...
// Now register the logging interceptor // Now register the interceptor
ExceptionHandlingInterceptor interceptor = new ExceptionHandlingInterceptor(); ExceptionHandlingInterceptor interceptor = new ExceptionHandlingInterceptor();
registerInterceptor(interceptor); registerInterceptor(interceptor);
@ -59,4 +60,22 @@ public class ServletExamples {
} }
// END SNIPPET: exceptionInterceptor // END SNIPPET: exceptionInterceptor
// START SNIPPET: responseHighlighterInterceptor
@WebServlet(urlPatterns = { "/fhir/*" }, displayName = "FHIR Server")
public class RestfulServerWithResponseHighlighter extends RestfulServer {
@Override
protected void initialize() throws ServletException {
// ... define your resource providers here ...
// Now register the interceptor
ResponseHighlighterInterceptor interceptor = new ResponseHighlighterInterceptor();
registerInterceptor(interceptor);
}
}
// END SNIPPET: responseHighlighterInterceptor
} }

View File

@ -277,7 +277,8 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Obje
// For POST the URL parameters get jumbled with the post body parameters so don't include them, they might be huge // For POST the URL parameters get jumbled with the post body parameters so don't include them, they might be huge
if (theRequest.getRequestType() == RequestTypeEnum.GET) { if (theRequest.getRequestType() == RequestTypeEnum.GET) {
boolean first = true; boolean first = true;
for (Entry<String, String[]> nextParams : theRequest.getParameters().entrySet()) { Map<String, String[]> parameters = theRequest.getParameters();
for (Entry<String, String[]> nextParams : parameters.entrySet()) {
for (String nextParamValue : nextParams.getValue()) { for (String nextParamValue : nextParams.getValue()) {
if (first) { if (first) {
b.append('?'); b.append('?');

View File

@ -170,7 +170,7 @@ public class RestfulServerUtils {
public static boolean prettyPrintResponse(RestfulServer theServer, RequestDetails theRequest) { public static boolean prettyPrintResponse(RestfulServer theServer, RequestDetails theRequest) {
Map<String, String[]> requestParams = theRequest.getParameters(); Map<String, String[]> requestParams = theRequest.getParameters();
String[] pretty = requestParams.remove(Constants.PARAM_PRETTY); String[] pretty = requestParams.get(Constants.PARAM_PRETTY);
boolean prettyPrint; boolean prettyPrint;
if (pretty != null && pretty.length > 0) { if (pretty != null && pretty.length > 0) {
if (Constants.PARAM_PRETTY_VALUE_TRUE.equals(pretty[0])) { if (Constants.PARAM_PRETTY_VALUE_TRUE.equals(pretty[0])) {
@ -304,7 +304,7 @@ public class RestfulServerUtils {
public static RestfulServer.NarrativeModeEnum determineNarrativeMode(RequestDetails theRequest) { public static RestfulServer.NarrativeModeEnum determineNarrativeMode(RequestDetails theRequest) {
Map<String, String[]> requestParams = theRequest.getParameters(); Map<String, String[]> requestParams = theRequest.getParameters();
String[] narrative = requestParams.remove(Constants.PARAM_NARRATIVE); String[] narrative = requestParams.get(Constants.PARAM_NARRATIVE);
RestfulServer.NarrativeModeEnum narrativeMode = null; RestfulServer.NarrativeModeEnum narrativeMode = null;
if (narrative != null && narrative.length > 0) { if (narrative != null && narrative.length > 0) {
try { try {

View File

@ -29,6 +29,7 @@ import org.apache.commons.lang3.StringEscapeUtils;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.method.RequestDetails; import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.EncodingEnum; import ca.uhn.fhir.rest.server.EncodingEnum;
@ -153,11 +154,30 @@ public class ResponseHighlighterInterceptor extends InterceptorAdapter {
@Override @Override
public boolean outgoingResponse(RequestDetails theRequestDetails, IBaseResource theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) public boolean outgoingResponse(RequestDetails theRequestDetails, IBaseResource theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse)
throws AuthenticationException { throws AuthenticationException {
/*
* It's not a browser...
*/
String accept = theServletRequest.getHeader(Constants.HEADER_ACCEPT); String accept = theServletRequest.getHeader(Constants.HEADER_ACCEPT);
if (accept == null || !accept.toLowerCase().contains("html")) { if (accept == null || !accept.toLowerCase().contains("html")) {
return super.outgoingResponse(theRequestDetails, theResponseObject, theServletRequest, theServletResponse); return super.outgoingResponse(theRequestDetails, theResponseObject, theServletRequest, theServletResponse);
} }
/*
* It's an AJAX request, so no HTML
*/
String requestedWith = theServletRequest.getHeader("X-Requested-With");
if (requestedWith != null) {
return super.outgoingResponse(theRequestDetails, theResponseObject, theServletRequest, theServletResponse);
}
/*
* Not a GET
*/
if (theRequestDetails.getRequestType() != RequestTypeEnum.GET) {
return super.outgoingResponse(theRequestDetails, theResponseObject, theServletRequest, theServletResponse);
}
// Pretty print // Pretty print
boolean prettyPrint = RestfulServerUtils.prettyPrintResponse(theRequestDetails.getServer(), theRequestDetails); boolean prettyPrint = RestfulServerUtils.prettyPrintResponse(theRequestDetails.getServer(), theRequestDetails);

View File

@ -244,12 +244,6 @@
<version>${guava_version}</version> <version>${guava_version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>${derby_version}</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlets</artifactId> <artifactId>jetty-servlets</artifactId>

View File

@ -25,6 +25,7 @@ import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy;
import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
public class TestRestfulServer extends RestfulServer { public class TestRestfulServer extends RestfulServer {
@ -120,7 +121,7 @@ public class TestRestfulServer extends RestfulServer {
} }
setResourceProviders(beans); setResourceProviders(beans);
List provList = new ArrayList(); List<Object> provList = new ArrayList<Object>();
if (systemProviderDstu1 != null) if (systemProviderDstu1 != null)
provList.add(systemProviderDstu1); provList.add(systemProviderDstu1);
if (systemProviderDstu2 != null) if (systemProviderDstu2 != null)
@ -128,12 +129,10 @@ public class TestRestfulServer extends RestfulServer {
setPlainProviders(provList); setPlainProviders(provList);
/* /*
* This tells the server to use "incorrect" MIME types if it detects that the * We want to format the response using nice HTML if it's a browser, since this
* request is coming from a browser in the hopes that the browser won't just treat * makes things a little easier for testers.
* the content as a binary payload and try to download it (which is what generally
* happens if you load a FHIR URL in a browser)
*/ */
setUseBrowserFriendlyContentTypes(true); registerInterceptor(new ResponseHighlighterInterceptor());
/* /*
* Default to XML and pretty printing * Default to XML and pretty printing

View File

@ -102,7 +102,7 @@ public class PlainProviderTest {
Patient patient = (Patient) bundle.getEntries().get(0).getResource(); Patient patient = (Patient) bundle.getEntries().get(0).getResource();
assertEquals("PatientOne", patient.getName().get(0).getGiven().get(0).getValue()); assertEquals("PatientOne", patient.getName().get(0).getGiven().get(0).getValue());
assertEquals(uri, bundle.getLinkSelf().getValue()); assertEquals(uri.replace(":hapitest:", "%3Ahapitest%3A"), bundle.getLinkSelf().getValue());
assertEquals(baseUri, bundle.getLinkBase().getValue()); assertEquals(baseUri, bundle.getLinkBase().getValue());
httpGet.releaseConnection(); httpGet.releaseConnection();

View File

@ -134,7 +134,7 @@ public class RestfulServerSelfReferenceTest {
Patient patient = (Patient) bundle.getEntries().get(0).getResource(); Patient patient = (Patient) bundle.getEntries().get(0).getResource();
assertEquals("PatientOne", patient.getName().get(0).getGiven().get(0).getValue()); assertEquals("PatientOne", patient.getName().get(0).getGiven().get(0).getValue());
assertEquals(uri, bundle.getLinkSelf().getValue()); assertEquals(uri.replace(":hapitest:", "%3Ahapitest%3A"), bundle.getLinkSelf().getValue());
assertEquals(baseUri, bundle.getLinkBase().getValue()); assertEquals(baseUri, bundle.getLinkBase().getValue());
} finally { } finally {
hServer.stop(); hServer.stop();

View File

@ -42,6 +42,8 @@ public class SearchWithDstu2BundleTest {
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
responseContent = responseContent.replace("_pretty=true&amp;_format=xml", "_format=xml&amp;_pretty=true");
ourLog.info(responseContent); ourLog.info(responseContent);
//@formatter:off //@formatter:off

View File

@ -79,12 +79,6 @@
<version>${jetty_version}</version> <version>${jetty_version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>${jetty_version}</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId> <artifactId>jetty-util</artifactId>

View File

@ -22,6 +22,11 @@
The self link in the Bundle returned by searches on the server does not respect the The self link in the Bundle returned by searches on the server does not respect the
server's address strategy (which resulted in an internal IP being shown on fhirtest.uhn.ca) server's address strategy (which resulted in an internal IP being shown on fhirtest.uhn.ca)
</action> </action>
<action type="add">
Introduce ResponseHighlighterInterceptor, which provides syntax highlighting on RESTful server responses
if the server detects that the request is coming from a browser. This interceptor has been added
to fhirtest.uhn.ca responses.
</action>
</release> </release>
<release version="1.0" date="2015-May-8"> <release version="1.0" date="2015-May-8">
<action type="add"> <action type="add">

View File

@ -173,6 +173,29 @@
</subsection> </subsection>
<subsection name="Response Syntax Highlighting">
<p>
The
<a href="./apidocs/ca/uhn/fhir/rest/server/interceptor/ResponseHighlighterInterceptor.html">ResponseHighlighterInterceptor</a>
(<a href="./xref/ca/uhn/fhir/rest/server/interceptor/ResponseHighlighterInterceptor.html">code</a>)
detects when a request is coming from a browser and returns HTML with syntax highlighted XML/JSON instead
of just the raw text. In other words, if a user uses a browser to request "http://foo/Patient/1" by typing
this address into their URL bar, they will get nice formatted HTML back with a human readable version
of the content. This is helpful for testers.
</p>
<p>
The following example shows how to register this interceptor within
a FHIR RESTful server.
</p>
<macro name="snippet">
<param name="id" value="responseHighlighterInterceptor" />
<param name="file" value="examples/src/main/java/example/ServletExamples.java" />
</macro>
</subsection>
</section> </section>
<section name="Creating Interceptors"> <section name="Creating Interceptors">