From 82c1e687fd1964d03a00a3da881e2b14ec536f8f Mon Sep 17 00:00:00 2001 From: James Agnew Date: Wed, 4 May 2016 11:48:50 -0400 Subject: [PATCH] Fix NPE in LoggingInterceptor --- .../interceptor/LoggingInterceptor.java | 55 +++++++----- .../server/servlet/ServletRequestDetails.java | 6 +- .../java/ca/uhn/fhir/jpa/dao/PathAndRef.java | 20 +++++ .../dao/dstu3/FhirResourceDaoDstu3Test.java | 52 ++++++------ ...roviderQuestionnaireResponseDstu3Test.java | 84 ++++++++++++++++++ .../ca/uhn/fhirtest/config/CommonConfig.java | 2 +- .../src/main/resources/logback.xml | 2 +- .../LoggingInterceptorDstu2Test.java | 85 +++++++++++++++++-- .../DefaultProfileValidationSupport.java | 3 + .../dstu3/validation/InstanceValidator.java | 2 +- .../uhn/fhir/parser/XmlParserDstu3Test.java | 4 +- 11 files changed, 254 insertions(+), 61 deletions(-) diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/LoggingInterceptor.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/LoggingInterceptor.java index 39d9faa90a4..436fd42eb6e 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/LoggingInterceptor.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/LoggingInterceptor.java @@ -1,5 +1,7 @@ package ca.uhn.fhir.rest.server.interceptor; +import static org.apache.commons.lang3.StringUtils.isNotBlank; + import java.io.IOException; /* @@ -31,12 +33,10 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.Charsets; -import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.text.StrLookup; import org.apache.commons.lang3.text.StrSubstitutor; -import org.apache.http.util.EncodingUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,15 +58,18 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; * * * ${idOrResourceName} - * The resource ID associated with this request, or the resource name if the request applies to a type but not an instance, or "" otherwise + * The resource ID associated with this request, or the resource name if the request applies to a type but not an + * instance, or "" otherwise * * * ${operationName} - * If the request is an extended operation (e.g. "$validate") this value will be the operation name, or "" otherwise + * If the request is an extended operation (e.g. "$validate") this value will be the operation name, or "" + * otherwise * * * ${operationType} - * A code indicating the operation type for this request, e.g. "read", "history-instance", "extended-operation-instance", etc.) + * A code indicating the operation type for this request, e.g. "read", "history-instance", + * "extended-operation-instance", etc.) * * * ${remoteAddr} @@ -74,7 +77,8 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; * * * ${requestHeader.XXXX} - * The value of the HTTP request header named XXXX. For example, a substitution variable named "${requestHeader.x-forwarded-for} will yield the value of the first header named "x-forwarded-for + * The value of the HTTP request header named XXXX. For example, a substitution variable named + * "${requestHeader.x-forwarded-for} will yield the value of the first header named "x-forwarded-for * ", or "" if none. * * @@ -83,15 +87,18 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; * * * ${responseEncodingNoDefault} - * The encoding format requested by the client via the _format parameter or the Accept header. Value will be "json" or "xml", or "" if the client did not explicitly request a format + * The encoding format requested by the client via the _format parameter or the Accept header. Value will be "json" + * or "xml", or "" if the client did not explicitly request a format * * * ${servletPath} - * The part of thre requesting URL that corresponds to the particular Servlet being called (see {@link HttpServletRequest#getServletPath()}) + * The part of thre requesting URL that corresponds to the particular Servlet being called (see + * {@link HttpServletRequest#getServletPath()}) * * * ${requestBodyFhir} - * The complete body of the request if the request has a FHIR content-type (this can be quite large!). Will emit an empty string if the content type is not a FHIR content type + * The complete body of the request if the request has a FHIR content-type (this can be quite large!). Will emit an + * empty string if the content type is not a FHIR content type * * * ${requestUrl} @@ -122,10 +129,9 @@ public class LoggingInterceptor extends InterceptorAdapter { public String getErrorMessageFormat() { return myErrorMessageFormat; } - + @Override - public boolean handleException(RequestDetails theRequestDetails, BaseServerResponseException theException, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) - throws ServletException, IOException { + public boolean handleException(RequestDetails theRequestDetails, BaseServerResponseException theException, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws ServletException, IOException { if (myLogExceptions) { // Perform any string substitutions from the message format StrLookup lookup = new MyLookup(theServletRequest, theException, theRequestDetails); @@ -187,7 +193,8 @@ public class LoggingInterceptor extends InterceptorAdapter { } /** - * Sets the message format itself. See the {@link LoggingInterceptor class documentation} for information on the format + * Sets the message format itself. See the {@link LoggingInterceptor class documentation} for information on the + * format */ public void setMessageFormat(String theMessageFormat) { Validate.notBlank(theMessageFormat, "Message format can not be null/empty"); @@ -290,16 +297,18 @@ public class LoggingInterceptor extends InterceptorAdapter { return myRequest.getMethod(); } else if (theKey.equals("requestBodyFhir")) { String contentType = myRequest.getContentType(); - int colonIndex = contentType.indexOf(';'); - if (colonIndex != -1) { - contentType = contentType.substring(0, colonIndex); - } - contentType = contentType.trim(); - - EncodingEnum encoding = EncodingEnum.forContentType(contentType); - if (encoding != null) { - byte[] requestContents = myRequestDetails.loadRequestContents(); - return new String(requestContents, Charsets.UTF_8); + if (isNotBlank(contentType)) { + int colonIndex = contentType.indexOf(';'); + if (colonIndex != -1) { + contentType = contentType.substring(0, colonIndex); + } + contentType = contentType.trim(); + + EncodingEnum encoding = EncodingEnum.forContentType(contentType); + if (encoding != null) { + byte[] requestContents = myRequestDetails.loadRequestContents(); + return new String(requestContents, Charsets.UTF_8); + } } return ""; } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/servlet/ServletRequestDetails.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/servlet/ServletRequestDetails.java index cc97eb5b3bd..556c9a816f5 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/servlet/ServletRequestDetails.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/servlet/ServletRequestDetails.java @@ -103,8 +103,10 @@ public class ServletRequestDetails extends RequestDetails { String contentEncoding = myServletRequest.getHeader(Constants.HEADER_CONTENT_ENCODING); if ("gzip".equals(contentEncoding)) { ourLog.debug("Uncompressing (GZip) incoming content"); - GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(requestContents)); - requestContents = IOUtils.toByteArray(gis); + if (requestContents.length > 0) { + GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(requestContents)); + requestContents = IOUtils.toByteArray(gis); + } } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/PathAndRef.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/PathAndRef.java index 79bbe93e473..a68b82db1c5 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/PathAndRef.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/PathAndRef.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.jpa.dao; +/* + * #%L + * HAPI FHIR JPA Server + * %% + * Copyright (C) 2014 - 2016 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + public class PathAndRef { private final String myPath; diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3Test.java index ed8ca7b2e63..108fa422640 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3Test.java @@ -9,6 +9,7 @@ import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.startsWith; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -32,6 +33,9 @@ import java.util.Map; import java.util.Set; import org.apache.commons.lang3.RandomStringUtils; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; import org.hamcrest.Matchers; import org.hamcrest.core.StringContains; import org.hl7.fhir.dstu3.model.BaseResource; @@ -118,7 +122,6 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test { TestUtil.clearAllStaticFieldsForUnitTest(); } - private void assertGone(IIdType theId) { try { assertNotGone(theId); @@ -240,7 +243,6 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test { } } - @Test public void testChoiceParamDate() { Observation o2 = new Observation(); @@ -254,7 +256,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test { assertEquals(id2, found.getResources(0, 1).get(0).getIdElement()); } } - + @Test public void testCreateDifferentTypesWithSameForcedId() { String idName = "forcedId"; @@ -264,17 +266,17 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test { pat.addName().addFamily("FAM"); IIdType patId = myPatientDao.update(pat, mySrd).getId(); assertEquals("Patient/" + idName, patId.toUnqualifiedVersionless().getValue()); - + Observation obs = new Observation(); obs.setId(idName); obs.getCode().addCoding().setSystem("foo").setCode("testCreateDifferentTypesWithSameForcedId"); IIdType obsId = myObservationDao.update(obs, mySrd).getId(); assertEquals("Observation/" + idName, obsId.toUnqualifiedVersionless().getValue()); - + pat = myPatientDao.read(patId.toUnqualifiedVersionless(), mySrd); obs = myObservationDao.read(obsId.toUnqualifiedVersionless(), mySrd); } - + @Test public void testChoiceParamDateAlt() { Observation o2 = new Observation(); @@ -468,7 +470,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test { NamingSystem res = myFhirCtx.newXmlParser().parseResource(NamingSystem.class, input); IIdType id = myNamingSystemDao.create(res, mySrd).getId().toUnqualifiedVersionless(); - + assertThat(toUnqualifiedVersionlessIdValues(myNamingSystemDao.search(NamingSystem.SP_NAME, new StringParam("NDF"))), contains(id.getValue())); } @@ -497,7 +499,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test { assertEquals("my message", oo.getIssue().get(0).getDiagnostics()); assertEquals(IssueType.INCOMPLETE, oo.getIssue().get(0).getCode()); } - + @Test public void testCreateOperationOutcomeInfo() { FhirResourceDaoDstu3 dao = new FhirResourceDaoDstu3(); @@ -593,7 +595,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test { myBundleDao.create(bundle, mySrd); } - + @Test public void testCreateWithIfNoneExistBasic() { String methodName = "testCreateWithIfNoneExistBasic"; @@ -773,7 +775,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test { // Lose typing so we can put the wrong type in @SuppressWarnings("rawtypes") IFhirResourceDao dao = myNamingSystemDao; - + Patient resource = new Patient(); resource.addName().addFamily("My Name"); try { @@ -1473,10 +1475,10 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test { @Test public void testHistoryWithFutureSinceDate() throws Exception { - + Date before = new Date(); Thread.sleep(10); - + Patient inPatient = new Patient(); inPatient.addName().addFamily("version1"); inPatient.getMeta().addProfile("http://example.com/1"); @@ -1484,18 +1486,18 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test { Thread.sleep(10); Date after = new Date(); - + // No since - + IBundleProvider history = myPatientDao.history(null, mySrd); assertEquals(1, history.size()); Patient outPatient = (Patient) history.getResources(0, 1).get(0); assertEquals("version1", inPatient.getName().get(0).getFamilyAsSingleString()); List profiles = toStringList(outPatient.getMeta().getProfile()); assertThat(profiles, contains("http://example.com/1")); - + // Before since - + history = myPatientDao.history(before, mySrd); assertEquals(1, history.size()); outPatient = (Patient) history.getResources(0, 1).get(0); @@ -1504,12 +1506,12 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test { assertThat(profiles, contains("http://example.com/1")); // After since - + history = myPatientDao.history(after, mySrd); assertEquals(0, history.size()); } - + @Test public void testHistoryReflectsMetaOperations() throws Exception { Patient inPatient = new Patient(); @@ -1523,25 +1525,25 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test { assertEquals("version1", inPatient.getName().get(0).getFamilyAsSingleString()); List profiles = toStringList(outPatient.getMeta().getProfile()); assertThat(profiles, contains("http://example.com/1")); - + /* * Change metadata */ - + inPatient.getMeta().addProfile("http://example.com/2"); myPatientDao.metaAddOperation(id, inPatient.getMeta(), mySrd); - + history = myPatientDao.history(null, mySrd); assertEquals(1, history.size()); outPatient = (Patient) history.getResources(0, 1).get(0); assertEquals("version1", inPatient.getName().get(0).getFamilyAsSingleString()); profiles = toStringList(outPatient.getMeta().getProfile()); assertThat(profiles, containsInAnyOrder("http://example.com/1", "http://example.com/2")); - + /* * Do an update */ - + inPatient.setId(id); inPatient.getMeta().addProfile("http://example.com/3"); inPatient.getName().get(0).addFamily("version2"); @@ -1559,7 +1561,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test { assertEquals("version1", outPatient.getName().get(0).getFamilyAsSingleString()); profiles = toStringList(outPatient.getMeta().getProfile()); assertThat(profiles, containsInAnyOrder("http://example.com/1", "http://example.com/2")); -} + } @Test public void testHistoryWithDeletedResource() throws Exception { @@ -1603,7 +1605,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test { assertEquals("Resource Patient/FOOFOOFOO is not known", e.getMessage()); } } - + @Test public void testIdParam() { Patient patient = new Patient(); diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderQuestionnaireResponseDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderQuestionnaireResponseDstu3Test.java index 18e1f858a28..6e380f2d839 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderQuestionnaireResponseDstu3Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderQuestionnaireResponseDstu3Test.java @@ -1,12 +1,23 @@ package ca.uhn.fhir.jpa.provider.dstu3; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.startsWith; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; +import java.io.IOException; import java.util.Collection; +import org.apache.commons.io.IOUtils; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; import org.hl7.fhir.dstu3.model.DecimalType; +import org.hl7.fhir.dstu3.model.IdType; import org.hl7.fhir.dstu3.model.Patient; import org.hl7.fhir.dstu3.model.Questionnaire; import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemType; @@ -17,6 +28,7 @@ import org.junit.AfterClass; import org.junit.Before; import org.junit.Test; +import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; @@ -99,5 +111,77 @@ public class ResourceProviderQuestionnaireResponseDstu3Test extends BaseResource assertThat(e.toString(), containsString("Answer value must be of type string")); } } + + @Test + public void testSaveQuestionnaire() throws Exception { + String input = "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + HttpPost post = new HttpPost(ourServerBase + "/QuestionnaireResponse"); + post.setEntity(new StringEntity(input, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + CloseableHttpResponse response = ourHttpClient.execute(post); + final IdType id2; + try { + String responseString = IOUtils.toString(response.getEntity().getContent()); + ourLog.info("Response: {}", responseString); + assertEquals(201, response.getStatusLine().getStatusCode()); + String newIdString = response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue(); + assertThat(newIdString, startsWith(ourServerBase + "/QuestionnaireResponse/")); + id2 = new IdType(newIdString); + } finally { + IOUtils.closeQuietly(response); + } + + HttpGet get = new HttpGet(ourServerBase + "/QuestionnaireResponse/" + id2.getIdPart() + "?_format=xml&_pretty=true"); + response = ourHttpClient.execute(get); + try { + String responseString = IOUtils.toString(response.getEntity().getContent()); + ourLog.info("Response: {}", responseString); + assertThat(responseString, containsString("Exclusion Criteria")); + } finally { + IOUtils.closeQuietly(response); + } + + + + } + } diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/config/CommonConfig.java b/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/config/CommonConfig.java index 078e9b63f1c..0d1b9620cc3 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/config/CommonConfig.java +++ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/config/CommonConfig.java @@ -30,7 +30,7 @@ public class CommonConfig { public IServerInterceptor requestLoggingInterceptor() { LoggingInterceptor retVal = new LoggingInterceptor(); retVal.setLoggerName("fhirtest.request"); - retVal.setMessageFormat("Path[${servletPath}] ${requestBodyFhir}"); + retVal.setMessageFormat("${requestVerb} ${servletPath} -\n${requestBodyFhir}"); retVal.setLogExceptions(false); return retVal; } diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/logback.xml b/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/logback.xml index 7716824761c..b0d0d5a9bdc 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/logback.xml +++ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/logback.xml @@ -73,7 +73,7 @@ - %d{yyyy-MM-dd HH:mm:ss.SSS} %msg%n + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %msg%n diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/interceptor/LoggingInterceptorDstu2Test.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/interceptor/LoggingInterceptorDstu2Test.java index 9ba41e36c96..b3b87623223 100644 --- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/interceptor/LoggingInterceptorDstu2Test.java +++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/interceptor/LoggingInterceptorDstu2Test.java @@ -70,11 +70,13 @@ public class LoggingInterceptorDstu2Test { private static Server ourServer; private static RestfulServer servlet; private IServerInterceptor myInterceptor; + private static Exception ourThrowException; @Before public void before() { myInterceptor = mock(IServerInterceptor.class); servlet.setInterceptors(Collections.singletonList(myInterceptor)); + ourThrowException = null; } @Test @@ -139,7 +141,48 @@ public class LoggingInterceptorDstu2Test { } @Test - public void testCreate() throws Exception { + public void testRequestBodyRead() throws Exception { + + LoggingInterceptor interceptor = new LoggingInterceptor(); + interceptor.setMessageFormat("${operationType} - ${operationName} - ${idOrResourceName} - ${requestBodyFhir}"); + servlet.setInterceptors(Collections.singletonList((IServerInterceptor) interceptor)); + + Logger logger = mock(Logger.class); + interceptor.setLogger(logger); + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1"); + + HttpResponse status = ourClient.execute(httpGet); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); + verify(logger, times(1)).info(captor.capture()); + assertEquals("read - - Patient/1 - ", captor.getValue()); + } + + @Test + public void testRequestBodyReadWithContentTypeHeader() throws Exception { + + LoggingInterceptor interceptor = new LoggingInterceptor(); + interceptor.setMessageFormat("${operationType} - ${operationName} - ${idOrResourceName} - ${requestBodyFhir}"); + servlet.setInterceptors(Collections.singletonList((IServerInterceptor) interceptor)); + + Logger logger = mock(Logger.class); + interceptor.setLogger(logger); + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1"); + httpGet.addHeader(Constants.HEADER_CONTENT_TYPE, Constants.CT_FHIR_XML); + + HttpResponse status = ourClient.execute(httpGet); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); + verify(logger, times(1)).info(captor.capture()); + assertEquals("read - - Patient/1 - ", captor.getValue()); + } + + @Test + public void testRequestBodyCreate() throws Exception { LoggingInterceptor interceptor = new LoggingInterceptor(); interceptor.setMessageFormat("${operationType} - ${operationName} - ${idOrResourceName} - ${requestBodyFhir}"); @@ -151,10 +194,37 @@ public class LoggingInterceptorDstu2Test { Patient p = new Patient(); p.addIdentifier().setValue("VAL"); String input = ourCtx.newXmlParser().encodeResourceToString(p); - + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); - httpPost.setEntity(new StringEntity(input, ContentType.parse(Constants.CT_FHIR_XML+";charset=utf-8"))); - + httpPost.setEntity(new StringEntity(input, ContentType.parse(Constants.CT_FHIR_XML + ";charset=utf-8"))); + + HttpResponse status = ourClient.execute(httpPost); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); + verify(logger, times(1)).info(captor.capture()); + assertEquals("create - - Patient - ", captor.getValue()); + } + + @Test + public void testRequestBodyCreateException() throws Exception { + + LoggingInterceptor interceptor = new LoggingInterceptor(); + interceptor.setMessageFormat("${operationType} - ${operationName} - ${idOrResourceName} - ${requestBodyFhir}"); + servlet.setInterceptors(Collections.singletonList((IServerInterceptor) interceptor)); + + Logger logger = mock(Logger.class); + interceptor.setLogger(logger); + + Patient p = new Patient(); + p.addIdentifier().setValue("VAL"); + String input = ourCtx.newXmlParser().encodeResourceToString(p); + + ourThrowException = new NullPointerException("FOO"); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); + httpPost.setEntity(new StringEntity(input, ContentType.parse(Constants.CT_FHIR_XML + ";charset=utf-8"))); + HttpResponse status = ourClient.execute(httpPost); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -348,10 +418,13 @@ public class LoggingInterceptorDstu2Test { } @Create - public MethodOutcome create(@ResourceParam Patient thePatient) { + public MethodOutcome create(@ResourceParam Patient thePatient) throws Exception { + if (ourThrowException != null) { + throw ourThrowException; + } return new MethodOutcome(new IdDt("Patient/1")); } - + @Operation(name = "$everything", idempotent = true) public Bundle patientTypeOperation(@OperationParam(name = "start") DateDt theStart, @OperationParam(name = "end") DateDt theEnd) { diff --git a/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/validation/DefaultProfileValidationSupport.java b/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/validation/DefaultProfileValidationSupport.java index 3e74dc71cc2..bc96dbc76ce 100644 --- a/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/validation/DefaultProfileValidationSupport.java +++ b/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/validation/DefaultProfileValidationSupport.java @@ -12,6 +12,7 @@ import java.util.Map; import java.util.Set; import org.apache.commons.io.Charsets; +import org.apache.commons.lang3.Validate; import org.hl7.fhir.dstu3.model.Bundle; import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent; import org.hl7.fhir.dstu3.model.CodeSystem; @@ -89,6 +90,8 @@ public class DefaultProfileValidationSupport implements IValidationSupport { @SuppressWarnings("unchecked") @Override public T fetchResource(FhirContext theContext, Class theClass, String theUri) { + Validate.notBlank(theUri, "theUri must not be null or blank"); + if (theUri.startsWith("http://hl7.org/fhir/StructureDefinition/")) { return (T) fetchStructureDefinition(theContext, theUri); } diff --git a/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/validation/InstanceValidator.java b/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/validation/InstanceValidator.java index a7c3b5335dd..3bcbb91485a 100644 --- a/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/validation/InstanceValidator.java +++ b/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/validation/InstanceValidator.java @@ -1541,7 +1541,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private void validateQuestionannaireResponse(List errors, Element element, NodeStack stack) { Element q = element.getNamedChild("questionnaire"); - if (hint(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), q != null, "No questionnaire is identified, so no validation can be performed against the base questionnaire")) { + if (hint(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), q != null && isNotBlank(q.getNamedChildValue("reference")), "No questionnaire is identified, so no validation can be performed against the base questionnaire")) { long t = System.nanoTime(); Questionnaire qsrc = context.fetchResource(Questionnaire.class, q.getNamedChildValue("reference")); sdTime = sdTime + (System.nanoTime() - t); diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/XmlParserDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/XmlParserDstu3Test.java index 8bbb3664402..d579851fd1f 100644 --- a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/XmlParserDstu3Test.java +++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/XmlParserDstu3Test.java @@ -120,14 +120,14 @@ public class XmlParserDstu3Test { } @Test - public void testEncodeContained() throws Exception { + public void testEncodeContainedWithNonLocalId() throws Exception { Patient p = new Patient(); p.setId("Patient1"); p.setBirthDate(new SimpleDateFormat("yyyy-mm-dd HH:mm:ss").parse("2016-04-15 10:15:30")); ProcedureRequest pr = new ProcedureRequest(); - pr.setId("#1234567"); + pr.setId("1234567"); pr.setSubject(new Reference(p)); pr.setCode(new CodeableConcept().addCoding(new Coding("breastfeeding-readiness-assessment", "Breastfeeding Readiness Assessment", "Breastfeeding Readiness Assessment"))); // pr.setReason(new StringType("Single Live Birth"));