From 685bd9345bbf599dafd4707916394d5303db0140 Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Sun, 3 Jan 2016 21:52:11 -0500 Subject: [PATCH] Add request/response validator interceptors --- .../main/java/example/ServletExamples.java | 41 ++ .../ca/uhn/fhir/rest/api/MethodOutcome.java | 1 + .../BaseOutcomeReturningMethodBinding.java | 81 ++-- .../fhir/rest/param/ResourceParameter.java | 56 ++- .../fhir/rest/param/TransactionParameter.java | 10 +- .../fhir/rest/server/IRestfulResponse.java | 23 +- .../BaseValidatingInterceptor.java | 235 +++++++++++ .../interceptor/IServerInterceptor.java | 373 +++++++++++------- .../RequestValidatingInterceptor.java | 71 ++++ .../ResponseValidatingInterceptor.java | 57 +-- .../servlet/ServletRestfulResponse.java | 90 ++--- .../uhn/fhir/jpa/config/BaseDstu21Config.java | 43 +- .../fhir/jpa/dao/BaseHapiFhirResourceDao.java | 44 +-- .../fhir/jpa/dao/BaseHapiFhirSystemDao.java | 6 +- .../fhir/jpa/dao/FhirResourceDaoDstu1.java | 2 +- .../fhir/jpa/dao/FhirResourceDaoDstu2.java | 5 +- .../fhir/jpa/dao/FhirResourceDaoDstu21.java | 58 +-- .../jpa/dao/FhirResourceDaoPatientDstu2.java | 4 +- .../jpa/dao/FhirResourceDaoPatientDstu21.java | 4 +- ...esourceDaoQuestionnaireResponseDstu21.java | 13 +- .../uhn/fhir/jpa/dao/FhirSystemDaoDstu1.java | 2 +- .../uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java | 4 +- .../uhn/fhir/jpa/dao/FhirSystemDaoDstu21.java | 4 +- .../dao/dstu2/FhirResourceDaoDstu2Test.java | 4 +- .../jpa/dao/dstu21/BaseJpaDstu21Test.java | 2 +- .../dao/dstu21/FhirResourceDaoDstu21Test.java | 5 +- .../ca/uhn/fhirtest/TestRestfulServer.java | 18 +- .../uhn/fhirtest/config/TestDstu21Config.java | 74 +++- .../FhirQuestionnaireResponseValidator.java | 3 +- .../fhir/dstu21/model/annotations/Block.java | 55 --- .../fhir/dstu21/model/annotations/Child.java | 165 -------- .../dstu21/model/annotations/DatatypeDef.java | 88 ----- .../dstu21/model/annotations/Description.java | 55 --- .../dstu21/model/annotations/Extension.java | 74 ---- .../dstu21/model/annotations/ResourceDef.java | 59 --- .../annotations/SearchParamDefinition.java | 79 ---- .../fhir/dstu21/model/api/IAnyResource.java | 34 -- .../dstu21/model/api/IBackboneElement.java | 26 -- .../org/hl7/fhir/dstu21/model/api/IBase.java | 32 -- .../model/api/IBaseBackboneElement.java | 26 -- .../fhir/dstu21/model/api/IBaseBinary.java | 37 -- .../model/api/IBaseBooleanDatatype.java | 26 -- .../fhir/dstu21/model/api/IBaseBundle.java | 48 --- .../fhir/dstu21/model/api/IBaseCoding.java | 31 -- .../dstu21/model/api/IBaseConformance.java | 6 - .../fhir/dstu21/model/api/IBaseDatatype.java | 26 -- .../model/api/IBaseDatatypeElement.java | 26 -- .../model/api/IBaseDecimalDatatype.java | 27 -- .../fhir/dstu21/model/api/IBaseElement.java | 27 -- .../dstu21/model/api/IBaseEnumFactory.java | 42 -- .../dstu21/model/api/IBaseEnumeration.java | 28 -- .../fhir/dstu21/model/api/IBaseExtension.java | 37 -- .../fhir/dstu21/model/api/IBaseFhirEnum.java | 66 ---- .../dstu21/model/api/IBaseHasExtensions.java | 31 -- .../model/api/IBaseHasModifierExtensions.java | 31 -- .../model/api/IBaseIntegerDatatype.java | 26 -- .../fhir/dstu21/model/api/IBaseMetaType.java | 35 -- .../model/api/IBaseOperationOutcome.java | 5 - .../dstu21/model/api/IBaseParameters.java | 26 -- .../fhir/dstu21/model/api/IBaseReference.java | 37 -- .../fhir/dstu21/model/api/IBaseResource.java | 40 -- .../hl7/fhir/dstu21/model/api/IBaseXhtml.java | 6 - .../fhir/dstu21/model/api/ICompositeType.java | 26 -- .../dstu21/model/api/IDomainResource.java | 31 -- .../hl7/fhir/dstu21/model/api/IIdType.java | 138 ------- .../hl7/fhir/dstu21/model/api/INarrative.java | 34 -- .../fhir/dstu21/model/api/IPrimitiveType.java | 35 -- .../RequestValidatingInterceptorTest.java | 311 +++++++++++++++ .../ResponseValidatingInterceptorTest.java | 253 ++++++++++++ .../FhirQuestionnaireResponseValidator.java | 3 +- pom.xml | 2 +- src/changes/changes.xml | 20 +- src/site/xdoc/doc_rest_server_interceptor.xml | 37 ++ src/site/xdoc/doc_validation.xml | 8 +- 74 files changed, 1536 insertions(+), 2052 deletions(-) create mode 100644 hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/BaseValidatingInterceptor.java create mode 100644 hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/RequestValidatingInterceptor.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/Block.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/Child.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/DatatypeDef.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/Description.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/Extension.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/ResourceDef.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/SearchParamDefinition.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IAnyResource.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBackboneElement.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBase.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseBackboneElement.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseBinary.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseBooleanDatatype.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseBundle.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseCoding.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseConformance.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseDatatype.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseDatatypeElement.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseDecimalDatatype.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseElement.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseEnumFactory.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseEnumeration.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseExtension.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseFhirEnum.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseHasExtensions.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseHasModifierExtensions.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseIntegerDatatype.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseMetaType.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseOperationOutcome.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseParameters.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseReference.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseResource.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseXhtml.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/ICompositeType.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IDomainResource.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IIdType.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/INarrative.java delete mode 100644 hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IPrimitiveType.java create mode 100644 hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/rest/server/RequestValidatingInterceptorTest.java create mode 100644 hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/rest/server/ResponseValidatingInterceptorTest.java diff --git a/examples/src/main/java/example/ServletExamples.java b/examples/src/main/java/example/ServletExamples.java index 518bf46b1dd..9a244b938f4 100644 --- a/examples/src/main/java/example/ServletExamples.java +++ b/examples/src/main/java/example/ServletExamples.java @@ -3,11 +3,16 @@ package example; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; +import org.hl7.fhir.instance.hapi.validation.FhirInstanceValidator; + import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.interceptor.ExceptionHandlingInterceptor; import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor; +import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor; import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor; +import ca.uhn.fhir.rest.server.interceptor.ResponseValidatingInterceptor; +import ca.uhn.fhir.validation.ResultSeverityEnum; @SuppressWarnings("serial") public class ServletExamples { @@ -38,6 +43,42 @@ public class ServletExamples { } // END SNIPPET: loggingInterceptor + // START SNIPPET: validatingInterceptor + @WebServlet(urlPatterns = { "/fhir/*" }, displayName = "FHIR Server") + public class ValidatingServerWithLogging extends RestfulServer { + + @Override + protected void initialize() throws ServletException { + + // ... define your resource providers here ... + + // Create an interceptor to validate incoming requests + RequestValidatingInterceptor requestInterceptor = new RequestValidatingInterceptor(); + + // Register a validator module (you could also use SchemaBaseValidator and/or SchematronBaseValidator) + requestInterceptor.addValidatorModule(new FhirInstanceValidator()); + + requestInterceptor.setFailOnSeverity(ResultSeverityEnum.ERROR); + requestInterceptor.setAddResponseHeaderOnSeverity(ResultSeverityEnum.INFORMATION); + requestInterceptor.setResponseHeaderValue("Validation on ${line}: ${message} ${severity}"); + requestInterceptor.setResponseHeaderValueNoIssues("No issues detected"); + + // Now register the validating interceptor + registerInterceptor(requestInterceptor); + + // Create an interceptor to validate responses + // This is configured in the same way as above + ResponseValidatingInterceptor responseInterceptor = new ResponseValidatingInterceptor(); + responseInterceptor.addValidatorModule(new FhirInstanceValidator()); + responseInterceptor.setFailOnSeverity(ResultSeverityEnum.ERROR); + responseInterceptor.setAddResponseHeaderOnSeverity(ResultSeverityEnum.INFORMATION); + responseInterceptor.setResponseHeaderValue("Validation on ${line}: ${message} ${severity}"); + responseInterceptor.setResponseHeaderValueNoIssues("No issues detected"); + registerInterceptor(responseInterceptor); + } + + } + // END SNIPPET: validatingInterceptor // START SNIPPET: exceptionInterceptor @WebServlet(urlPatterns = { "/fhir/*" }, displayName = "FHIR Server") diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/MethodOutcome.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/MethodOutcome.java index d148828dfa7..ae3d17a58f7 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/MethodOutcome.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/MethodOutcome.java @@ -38,6 +38,7 @@ public class MethodOutcome { * Constructor */ public MethodOutcome() { + super(); } /** diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java index ee5e66dba83..079c47be545 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java @@ -32,6 +32,7 @@ import java.util.Set; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; +import org.hl7.fhir.instance.model.api.IBaseOperationOutcome; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; @@ -48,11 +49,13 @@ import ca.uhn.fhir.rest.client.BaseHttpClientInvocation; import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.EncodingEnum; import ca.uhn.fhir.rest.server.IRestfulServer; +import ca.uhn.fhir.rest.server.IRestfulServerDefaults; import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.RestfulServerUtils; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; +import ca.uhn.fhir.util.OperationOutcomeUtil; abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding { static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseOutcomeReturningMethodBinding.class); @@ -64,8 +67,7 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding> theHeaders) throws BaseServerResponseException { - switch (theResponseStatusCode) { - case Constants.STATUS_HTTP_200_OK: - case Constants.STATUS_HTTP_201_CREATED: - case Constants.STATUS_HTTP_204_NO_CONTENT: + if (theResponseStatusCode >= 200 && theResponseStatusCode < 300) { if (myReturnVoid) { return null; } MethodOutcome retVal = MethodUtil.process2xxResponse(getContext(), getResourceName(), theResponseStatusCode, theResponseMimeType, theResponseReader, theHeaders); return retVal; - default: + } else { throw processNon2xxResponseAndReturnExceptionToThrow(theResponseStatusCode, theResponseMimeType, theResponseReader); } - } - + @Override public Object invokeServer(IRestfulServer theServer, RequestDetails theRequest) throws BaseServerResponseException, IOException { -// if (requestContainsResource()) { -// requestContents = parseIncomingServerResource(theRequest); -// } else { -// requestContents = null; -// } Object[] params = createParametersForServerRequest(theRequest); addParametersForServerRequest(theRequest, params); - /* - * No need to catch nd handle exceptions here, we already handle them one level up - * including invoking interceptors on them + * No need to catch and handle exceptions here, we already handle them one level up including invoking interceptors + * on them */ MethodOutcome response; -// try { - response = (MethodOutcome) invokeServerMethod(theServer, theRequest, params); -// } catch (InternalErrorException e) { -// ourLog.error("Internal error during method invocation", e); -// EncodingEnum encodingNotNull = RestfulServerUtils.determineResponseEncodingWithDefault(theServer, theRequest.getServletRequest()); -// streamOperationOutcome(e, theServer, encodingNotNull, servletResponse, theRequest); -// return; -// } catch (BaseServerResponseException e) { -// ourLog.info("Exception during method invocation: " + e.getMessage()); -// EncodingEnum encodingNotNull = RestfulServerUtils.determineResponseEncodingWithDefault(theServer, theRequest.getServletRequest()); -// streamOperationOutcome(e, theServer, encodingNotNull, servletResponse, theRequest); -// return; -// } + response = (MethodOutcome) invokeServerMethod(theServer, theRequest, params); if (response != null && response.getId() != null && response.getId().hasResourceType()) { if (getContext().getResourceDefinition(response.getId().getResourceType()) == null) { @@ -161,25 +142,17 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding= 0; i--) { - IServerInterceptor next = theServer.getInterceptors().get(i); - boolean continueProcessing = next.outgoingResponse(theRequest, outcome); - if (!continueProcessing) { - return null; - } - } - return returnResponse(theRequest, response, outcome, resource); + return returnResponse(theServer, theRequest, response, outcome, resource); } - + private int getOperationStatus(MethodOutcome response) { switch (getRestOperationType()) { case CREATE: if (response == null) { - throw new InternalErrorException("Method " + getMethod().getName() + " in type " + getMethod().getDeclaringClass().getCanonicalName() - + " returned null, which is not allowed for create operation"); + throw new InternalErrorException("Method " + getMethod().getName() + " in type " + getMethod().getDeclaringClass().getCanonicalName() + " returned null, which is not allowed for create operation"); } if (response.getCreated() == null || Boolean.TRUE.equals(response.getCreated())) { return Constants.STATUS_HTTP_201_CREATED; @@ -212,15 +185,14 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding theServer, RequestDetails theRequest, MethodOutcome response, IBaseResource originalOutcome, IBaseResource resource) throws IOException { boolean allowPrefer = false; int operationStatus = getOperationStatus(response); IBaseResource outcome = originalOutcome; - - if(EnumSet.of(RestOperationTypeEnum.CREATE, RestOperationTypeEnum.UPDATE).contains(getRestOperationType())) { + + if (EnumSet.of(RestOperationTypeEnum.CREATE, RestOperationTypeEnum.UPDATE).contains(getRestOperationType())) { allowPrefer = true; } - if (resource != null && allowPrefer) { String prefer = theRequest.getHeader(Constants.HEADER_PREFER); @@ -230,8 +202,16 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding= 0; i--) { + IServerInterceptor next = theServer.getInterceptors().get(i); + boolean continueProcessing = next.outgoingResponse(theRequest, outcome); + if (!continueProcessing) { + return null; + } + } + return theRequest.getResponse().returnResponse(ParseAction.create(outcome), operationStatus, allowPrefer, response, getResourceName()); } @@ -241,8 +221,7 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding provideAllowableRequestTypes(); - protected void streamOperationOutcome(BaseServerResponseException theE, RestfulServer theServer, EncodingEnum theEncodingNotNull, HttpServletResponse theResponse, RequestDetails theRequest) - throws IOException { + protected void streamOperationOutcome(BaseServerResponseException theE, RestfulServer theServer, EncodingEnum theEncodingNotNull, HttpServletResponse theResponse, RequestDetails theRequest) throws IOException { theResponse.setStatus(theE.getStatusCode()); theServer.addHeadersToResponse(theResponse); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ResourceParameter.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ResourceParameter.java index cc428ff2aab..d92faaa51a7 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ResourceParameter.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ResourceParameter.java @@ -94,41 +94,38 @@ public class ResourceParameter implements IParameter { } @Override - public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map> theTargetQueryArguments, IBaseResource theTargetResource) - throws InternalErrorException { + public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException { // TODO Auto-generated method stub } @Override - public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding theMethodBinding) - throws InternalErrorException, InvalidRequestException { - switch (myMode) { - case BODY: - try { - return IOUtils.toString(createRequestReader(theRequest)); - } - catch (IOException e) { - // Shouldn't happen since we're reading from a byte array - throw new InternalErrorException("Failed to load request"); - } - case ENCODING: - return RestfulServerUtils.determineRequestEncoding(theRequest); - case RESOURCE: - default: - return parseResourceFromRequest(theRequest, theMethodBinding, myResourceType); + public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding theMethodBinding) throws InternalErrorException, InvalidRequestException { + switch (myMode) { + case BODY: + try { + return IOUtils.toString(createRequestReader(theRequest)); + } catch (IOException e) { + // Shouldn't happen since we're reading from a byte array + throw new InternalErrorException("Failed to load request"); } -// } + case ENCODING: + return RestfulServerUtils.determineRequestEncoding(theRequest); + case RESOURCE: + default: + return parseResourceFromRequest(theRequest, theMethodBinding, myResourceType); + } + // } } - + public static Reader createRequestReader(RequestDetails theRequest, Charset charset) { Reader requestReader = new InputStreamReader(new ByteArrayInputStream(theRequest.loadRequestContents()), charset); return requestReader; } - public static Reader createRequestReader(RequestDetails theRequest) throws IOException { + public static Reader createRequestReader(RequestDetails theRequest) { return createRequestReader(theRequest, determineRequestCharset(theRequest)); - } + } public static Charset determineRequestCharset(RequestDetails theRequest) { String ct = theRequest.getHeader(Constants.HEADER_CONTENT_TYPE); @@ -142,11 +139,10 @@ public class ResourceParameter implements IParameter { charset = Charset.forName("UTF-8"); } return charset; - } - + } + @SuppressWarnings("unchecked") - public static T loadResourceFromRequest(RequestDetails theRequest, BaseMethodBinding theMethodBinding, - Class theResourceType) { + public static T loadResourceFromRequest(RequestDetails theRequest, BaseMethodBinding theMethodBinding, Class theResourceType) { FhirContext ctx = theRequest.getServer().getFhirContext(); final Charset charset = determineRequestCharset(theRequest); @@ -170,7 +166,7 @@ public class ResourceParameter implements IParameter { String body; try { body = IOUtils.toString(requestReader); - } catch (IOException e) { + } catch (IOException e) { // This shouldn't happen since we're reading from a byte array.. throw new InternalErrorException(e); } @@ -210,8 +206,8 @@ public class ResourceParameter implements IParameter { } } return retVal; - } - + } + public static IBaseResource parseResourceFromRequest(RequestDetails theRequest, BaseMethodBinding theMethodBinding, Class theResourceType) { IBaseResource retVal; if (IBaseBinary.class.isAssignableFrom(theResourceType)) { @@ -226,7 +222,7 @@ public class ResourceParameter implements IParameter { retVal = loadResourceFromRequest(theRequest, theMethodBinding, theResourceType); } return retVal; - } + } public enum Mode { BODY, ENCODING, RESOURCE diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/TransactionParameter.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/TransactionParameter.java index 2c56a61110f..fa13757d266 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/TransactionParameter.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/TransactionParameter.java @@ -1,7 +1,5 @@ package ca.uhn.fhir.rest.param; -import java.io.IOException; - /* * #%L * HAPI FHIR - Core Library @@ -108,13 +106,7 @@ public class TransactionParameter implements IParameter { IParser parser = encoding.newParser(theRequest.getServer().getFhirContext()); Reader reader; - try { - reader = ResourceParameter.createRequestReader(theRequest); - } - catch (IOException e) { - ourLog.error("Could not load request resource", e); - throw new InvalidRequestException(String.format("Could not load request resource: %s", e.getMessage())); - } + reader = ResourceParameter.createRequestReader(theRequest); switch (myParamStyle) { case DSTU1_BUNDLE: { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IRestfulResponse.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IRestfulResponse.java index a88aa73711b..62dc3a6cd3e 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IRestfulResponse.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IRestfulResponse.java @@ -35,17 +35,18 @@ import ca.uhn.fhir.rest.method.ParseAction; public interface IRestfulResponse { - Object streamResponseAsResource(IBaseResource resource, boolean prettyPrint, Set summaryMode, int operationStatus, boolean respondGzip, boolean addContentLocationHeader) - throws IOException; - Object streamResponseAsBundle(Bundle bundle, Set summaryMode, boolean respondGzip, boolean requestIsBrowser) - throws IOException; + Object streamResponseAsResource(IBaseResource resource, boolean prettyPrint, Set summaryMode, int operationStatus, boolean respondGzip, boolean addContentLocationHeader) throws IOException; - Object returnResponse(ParseAction outcome, int operationStatus, boolean allowPrefer, MethodOutcome response, String resourceName) throws IOException; - - Writer getResponseWriter(int statusCode, String contentType, String charset, boolean respondGzip) throws UnsupportedEncodingException, IOException; - Object sendWriterResponse(int status, String contentType, String charset, Writer writer) throws IOException; - - void addHeader(String headerKey, String headerValue); + Object streamResponseAsBundle(Bundle bundle, Set summaryMode, boolean respondGzip, boolean requestIsBrowser) throws IOException; + + Object returnResponse(ParseAction outcome, int operationStatus, boolean allowPrefer, MethodOutcome response, String resourceName) throws IOException; + + Writer getResponseWriter(int statusCode, String contentType, String charset, boolean respondGzip) throws UnsupportedEncodingException, IOException; + + Object sendWriterResponse(int status, String contentType, String charset, Writer writer) throws IOException; + + void addHeader(String headerKey, String headerValue); + + Object sendAttachmentResponse(IBaseBinary bin, int stausCode, String contentType) throws IOException; - Object sendAttachmentResponse(IBaseBinary bin, int stausCode, String contentType) throws IOException; } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/BaseValidatingInterceptor.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/BaseValidatingInterceptor.java new file mode 100644 index 00000000000..e91e32cfe72 --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/BaseValidatingInterceptor.java @@ -0,0 +1,235 @@ +package ca.uhn.fhir.rest.server.interceptor; + +import static org.apache.commons.lang3.StringUtils.isNotBlank; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.Validate; +import org.apache.commons.lang3.text.StrLookup; +import org.apache.commons.lang3.text.StrSubstitutor; + +import ca.uhn.fhir.rest.method.RequestDetails; +import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; +import ca.uhn.fhir.validation.FhirValidator; +import ca.uhn.fhir.validation.IValidatorModule; +import ca.uhn.fhir.validation.ResultSeverityEnum; +import ca.uhn.fhir.validation.SingleValidationMessage; +import ca.uhn.fhir.validation.ValidationResult; + +/** + * This interceptor intercepts each incoming request and if it contains a FHIR resource, validates that resource. The + * interceptor may be configured to run any validator modules, and will then add headers to the response or fail the + * request with an {@link UnprocessableEntityException HTTP 422 Unprocessable Entity}. + */ +abstract class BaseValidatingInterceptor extends InterceptorAdapter { + + /** + * Default value:
+ * + * ${row}:${col} ${severity} ${message} (${location}) + * + */ + public static final String DEFAULT_RESPONSE_HEADER_VALUE = "${row}:${col} ${severity} ${message} (${location})"; + + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseValidatingInterceptor.class); + + private Integer myAddResponseHeaderOnSeverity = ResultSeverityEnum.INFORMATION.ordinal(); + private Integer myFailOnSeverity = ResultSeverityEnum.ERROR.ordinal(); + private String myResponseHeaderName = provideDefaultResponseHeaderName(); + private String myResponseHeaderValue = DEFAULT_RESPONSE_HEADER_VALUE; + private String myResponseHeaderValueNoIssues = null; + + private List myValidatorModules; + + private void addResponseHeader(RequestDetails theRequestDetails, SingleValidationMessage theNext) { + // Perform any string substitutions from the message format + StrLookup lookup = new MyLookup(theNext); + StrSubstitutor subs = new StrSubstitutor(lookup, "${", "}", '\\'); + + // Log the header + String headerValue = subs.replace(myResponseHeaderValue); + ourLog.trace("Adding header to response: {}", headerValue); + + theRequestDetails.getResponse().addHeader(myResponseHeaderName, headerValue); + } + + public BaseValidatingInterceptor addValidatorModule(IValidatorModule theModule) { + Validate.notNull(theModule, "theModule must not be null"); + if (getValidatorModules() == null) { + setValidatorModules(new ArrayList()); + } + getValidatorModules().add(theModule); + return this; + } + + abstract ValidationResult doValidate(FhirValidator theValidator, T theRequest); + + /** + * Fail the request by throwing an {@link UnprocessableEntityException} as a result of a validation failure. + * Subclasses may change this behaviour by providing alternate behaviour. + */ + protected void fail(RequestDetails theRequestDetails, ValidationResult theValidationResult) { + throw new UnprocessableEntityException(theRequestDetails.getServer().getFhirContext(), theValidationResult.toOperationOutcome()); + } + + public List getValidatorModules() { + return myValidatorModules; + } + + abstract String provideDefaultResponseHeaderName(); + + /** + * Sets the minimum severity at which an issue detected by the validator will result in a header being added to the + * response. Default is {@link ResultSeverityEnum#INFORMATION}. Set to null to disable this behaviour. + * + * @see #setResponseHeaderName(String) + * @see #setResponseHeaderValue(String) + */ + public void setAddResponseHeaderOnSeverity(ResultSeverityEnum theSeverity) { + myAddResponseHeaderOnSeverity = theSeverity != null ? theSeverity.ordinal() : null; + } + + /** + * Sets the minimum severity at which an issue detected by the validator will fail/reject the request. Default is + * {@link ResultSeverityEnum#ERROR}. Set to null to disable this behaviour. + */ + public void setFailOnSeverity(ResultSeverityEnum theSeverity) { + myFailOnSeverity = theSeverity != null ? theSeverity.ordinal() : null; + } + + /** + * Sets the name of the response header to add validation failures to + * + * @see #setAddResponseHeaderOnSeverity(ResultSeverityEnum) + */ + protected void setResponseHeaderName(String theResponseHeaderName) { + Validate.notBlank(theResponseHeaderName, "theResponseHeaderName must not be blank or null"); + myResponseHeaderName = theResponseHeaderName; + } + + /** + * Sets the value to add to the response header with the name specified by {@link #setResponseHeaderName(String)} + * when validation produces a message of severity equal to or greater than + * {@link #setAddResponseHeaderOnSeverity(ResultSeverityEnum)} + *

+ * This field allows the following substitutions: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
NameValue
${line}The line in the request
${col}The column in the request
${location}The location in the payload as a string (typically this will be a path)
${severity}The severity of the issue
${message}The validation message
+ * + * @see #DEFAULT_RESPONSE_HEADER_VALUE + * @see #setAddResponseHeaderOnSeverity(ResultSeverityEnum) + */ + public void setResponseHeaderValue(String theResponseHeaderValue) { + Validate.notBlank(theResponseHeaderValue, "theResponseHeaderValue must not be blank or null"); + myResponseHeaderValue = theResponseHeaderValue; + } + + /** + * Sets the header value to add when no issues are found at or exceeding the + * threshold specified by {@link #setAddResponseHeaderOnSeverity(ResultSeverityEnum)} + */ + public void setResponseHeaderValueNoIssues(String theResponseHeaderValueNoIssues) { + myResponseHeaderValueNoIssues = theResponseHeaderValueNoIssues; + } + + public void setValidatorModules(List theValidatorModules) { + myValidatorModules = theValidatorModules; + } + + protected void validate(T theRequest, RequestDetails theRequestDetails) { + FhirValidator validator = theRequestDetails.getServer().getFhirContext().newValidator(); + if (myValidatorModules != null) { + for (IValidatorModule next : myValidatorModules) { + validator.registerValidatorModule(next); + } + } + + ValidationResult validationResult = doValidate(validator, theRequest); + + if (myAddResponseHeaderOnSeverity != null) { + boolean found = false; + for (SingleValidationMessage next : validationResult.getMessages()) { + if (next.getSeverity().ordinal() >= myAddResponseHeaderOnSeverity) { + addResponseHeader(theRequestDetails, next); + found = true; + } + } + if (!found) { + if (isNotBlank(myResponseHeaderValueNoIssues)) { + theRequestDetails.getResponse().addHeader(myResponseHeaderName, myResponseHeaderValueNoIssues); + } + } + } + + if (myFailOnSeverity != null) { + for (SingleValidationMessage next : validationResult.getMessages()) { + if (next.getSeverity().ordinal() >= myFailOnSeverity) { + fail(theRequestDetails, validationResult); + return; + } + } + } + } + + private static class MyLookup extends StrLookup { + + private SingleValidationMessage myMessage; + + public MyLookup(SingleValidationMessage theMessage) { + myMessage = theMessage; + } + + @Override + public String lookup(String theKey) { + if ("line".equals(theKey)) { + return toString(myMessage.getLocationLine()); + } + if ("col".equals(theKey)) { + return toString(myMessage.getLocationCol()); + } + if ("message".equals(theKey)) { + return toString(myMessage.getMessage()); + } + if ("location".equals(theKey)) { + return toString(myMessage.getLocationString()); + } + if ("severity".equals(theKey)) { + return myMessage.getSeverity() != null ? myMessage.getSeverity().name() : null; + } + + return ""; + } + + private static String toString(Object theInt) { + return theInt != null ? theInt.toString() : ""; + } + + } + +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/IServerInterceptor.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/IServerInterceptor.java index bf18100668f..4c9a565c503 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/IServerInterceptor.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/IServerInterceptor.java @@ -29,6 +29,7 @@ import javax.servlet.http.HttpServletResponse; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; +import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.base.resource.BaseOperationOutcome; @@ -41,41 +42,50 @@ import ca.uhn.fhir.rest.server.exceptions.AuthenticationException; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; /** - * Provides methods to intercept requests and responses. Note that implementations of this interface may wish to use {@link InterceptorAdapter} in order to not need to implement every method. + * Provides methods to intercept requests and responses. Note that implementations of this interface may wish to use + * {@link InterceptorAdapter} in order to not need to implement every method. *

- * See: See the server interceptor documentation for more information on how to use this class. + * See: See the server + * interceptor documentation for more information on how to use this class. *

*/ public interface IServerInterceptor { /** - * This method is called upon any exception being thrown within the server's request processing code. This includes any exceptions thrown within resource provider methods (e.g. {@link Search} and - * {@link Read} methods) as well as any runtime exceptions thrown by the server itself. This also includes any {@link AuthenticationException}s thrown. + * This method is called upon any exception being thrown within the server's request processing code. This includes + * any exceptions thrown within resource provider methods (e.g. {@link Search} and {@link Read} methods) as well as + * any runtime exceptions thrown by the server itself. This also includes any {@link AuthenticationException}s + * thrown. *

- * Implementations of this method may choose to ignore/log/count/etc exceptions, and return true. In this case, processing will continue, and the server will automatically generate an - * {@link BaseOperationOutcome OperationOutcome}. Implementations may also choose to provide their own response to the client. In this case, they should return false, to indicate that - * they have handled the request and processing should stop. + * Implementations of this method may choose to ignore/log/count/etc exceptions, and return true. In + * this case, processing will continue, and the server will automatically generate an {@link BaseOperationOutcome + * OperationOutcome}. Implementations may also choose to provide their own response to the client. In this case, they + * should return false, to indicate that they have handled the request and processing should stop. *

* * * @param theRequestDetails - * A bean containing details about the request that is about to be processed, including details such as the resource type and logical ID (if any) and other FHIR-specific aspects of the - * request which have been pulled out of the {@link javax.servlet.http.HttpServletRequest servlet request}. Note that the bean properties are not all guaranteed to be populated, depending - * on how early during processing the exception occurred. + * A bean containing details about the request that is about to be processed, including details such as the + * resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been + * pulled out of the {@link javax.servlet.http.HttpServletRequest servlet request}. Note that the bean + * properties are not all guaranteed to be populated, depending on how early during processing the + * exception occurred. * @param theServletRequest * The incoming request * @param theServletResponse - * The response. Note that interceptors may choose to provide a response (i.e. by calling {@link javax.servlet.http.HttpServletResponse#getWriter()}) but in that case it is important to - * return false to indicate that the server itself should not also provide a response. - * @return Return true if processing should continue normally. This is generally the right thing to do. If your interceptor is providing a response rather than letting HAPI handle the - * response normally, you must return false. In this case, no further processing will occur and no further interceptors will be called. + * The response. Note that interceptors may choose to provide a response (i.e. by calling + * {@link javax.servlet.http.HttpServletResponse#getWriter()}) but in that case it is important to return + * false to indicate that the server itself should not also provide a response. + * @return Return true if processing should continue normally. This is generally the right thing to do. + * If your interceptor is providing a response rather than letting HAPI handle the response normally, you + * must return false. In this case, no further processing will occur and no further interceptors + * will be called. * @throws ServletException * If this exception is thrown, it will be re-thrown up to the container for handling. * @throws IOException * If this exception is thrown, it will be re-thrown up to the container for handling. */ - boolean handleException(RequestDetails theRequestDetails, BaseServerResponseException theException, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) - throws ServletException, IOException; + boolean handleException(RequestDetails theRequestDetails, BaseServerResponseException theException, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws ServletException, IOException; /** * This method is called just before the actual implementing server method is invoked. @@ -84,18 +94,22 @@ public interface IServerInterceptor { *

* * @param theRequestDetails - * A bean containing details about the request that is about to be processed, including details such as the resource type and logical ID (if any) and other FHIR-specific aspects of the - * request which have been pulled out of the {@link HttpServletRequest servlet request}. + * A bean containing details about the request that is about to be processed, including details such as the + * resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been + * pulled out of the {@link HttpServletRequest servlet request}. * @param theRequest * The incoming request * @param theResponse - * The response. Note that interceptors may choose to provide a response (i.e. by calling {@link HttpServletResponse#getWriter()}) but in that case it is important to return - * false to indicate that the server itself should not also provide a response. - * @return Return true if processing should continue normally. This is generally the right thing to do. If your interceptor is providing a response rather than letting HAPI handle the - * response normally, you must return false. In this case, no further processing will occur and no further interceptors will be called. + * The response. Note that interceptors may choose to provide a response (i.e. by calling + * {@link HttpServletResponse#getWriter()}) but in that case it is important to return false + * to indicate that the server itself should not also provide a response. + * @return Return true if processing should continue normally. This is generally the right thing to do. + * If your interceptor is providing a response rather than letting HAPI handle the response normally, you + * must return false. In this case, no further processing will occur and no further interceptors + * will be called. * @throws AuthenticationException - * This exception may be thrown to indicate that the interceptor has detected an unauthorized access attempt. If thrown, processing will stop and an HTTP 401 will be returned to the - * client. + * This exception may be thrown to indicate that the interceptor has detected an unauthorized access + * attempt. If thrown, processing will stop and an HTTP 401 will be returned to the client. */ boolean incomingRequestPostProcessed(RequestDetails theRequestDetails, HttpServletRequest theRequest, HttpServletResponse theResponse) throws AuthenticationException; @@ -107,14 +121,14 @@ public interface IServerInterceptor { * @param theOperation * The type of operation that the FHIR server has determined that the client is trying to invoke * @param theProcessedRequest - * An object which will be populated with the details which were extracted from the raw request by the server, - * e.g. the FHIR operation type and the parsed resource body (if any). + * An object which will be populated with the details which were extracted from the raw request by the + * server, e.g. the FHIR operation type and the parsed resource body (if any). */ void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theProcessedRequest); /** - * This method is called before any other processing takes place for each incoming request. It may be used to provide alternate handling for some requests, or to screen requests before they are - * handled, etc. + * This method is called before any other processing takes place for each incoming request. It may be used to provide + * alternate handling for some requests, or to screen requests before they are handled, etc. *

* Note that any exceptions thrown by this method will not be trapped by HAPI (they will be passed up to the server) *

@@ -122,15 +136,19 @@ public interface IServerInterceptor { * @param theRequest * The incoming request * @param theResponse - * The response. Note that interceptors may choose to provide a response (i.e. by calling {@link HttpServletResponse#getWriter()}) but in that case it is important to return - * false to indicate that the server itself should not also provide a response. - * @return Return true if processing should continue normally. This is generally the right thing to do. If your interceptor is providing a response rather than letting HAPI handle the - * response normally, you must return false. In this case, no further processing will occur and no further interceptors will be called. + * The response. Note that interceptors may choose to provide a response (i.e. by calling + * {@link HttpServletResponse#getWriter()}) but in that case it is important to return false + * to indicate that the server itself should not also provide a response. + * @return Return true if processing should continue normally. This is generally the right thing to do. + * If your interceptor is providing a response rather than letting HAPI handle the response normally, you + * must return false. In this case, no further processing will occur and no further interceptors + * will be called. */ boolean incomingRequestPreProcessed(HttpServletRequest theRequest, HttpServletResponse theResponse); /** - * This method is called after the server implementation method has been called, but before any attempt to stream the response back to the client + * This method is called after the server implementation method has been called, but before any attempt to stream the + * response back to the client * * @param theRequestDetails * A bean containing details about the request that is about to be processed, including @@ -139,159 +157,198 @@ public interface IServerInterceptor { * @param theServletRequest * The incoming request * @param theServletResponse - * The response. Note that interceptors may choose to provide a response (i.e. by calling {@link HttpServletResponse#getWriter()}) but in that case it is important to return - * false to indicate that the server itself should not also provide a response. - * @return Return true if processing should continue normally. This is generally the right thing to do. If your interceptor is providing a response rather than letting HAPI handle the - * response normally, you must return false. In this case, no further processing will occur and no further interceptors will be called. + * The response. Note that interceptors may choose to provide a response (i.e. by calling + * {@link HttpServletResponse#getWriter()}) but in that case it is important to return false + * to indicate that the server itself should not also provide a response. + * @return Return true if processing should continue normally. This is generally the right thing to do. + * If your interceptor is providing a response rather than letting HAPI handle the response normally, you + * must return false. In this case, no further processing will occur and no further interceptors + * will be called. * @throws AuthenticationException - * This exception may be thrown to indicate that the interceptor has detected an unauthorized access attempt. If thrown, processing will stop and an HTTP 401 will be returned to the - * client. + * This exception may be thrown to indicate that the interceptor has detected an unauthorized access + * attempt. If thrown, processing will stop and an HTTP 401 will be returned to the client. */ boolean outgoingResponse(RequestDetails theRequestDetails, Bundle theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws AuthenticationException; - - /** - * This method is called after the server implementation method has been called, but before any attempt to stream the response back to the client - * - * @param theRequestDetails - * A bean containing details about the request that is about to be processed, including - * @param theResponseObject - * The actual object which is being streamed to the client as a response - * @param theServletRequest - * The incoming request - * @param theServletResponse - * The response. Note that interceptors may choose to provide a response (i.e. by calling {@link HttpServletResponse#getWriter()}) but in that case it is important to return - * false to indicate that the server itself should not also provide a response. - * @return Return true if processing should continue normally. This is generally the right thing to do. If your interceptor is providing a response rather than letting HAPI handle the - * response normally, you must return false. In this case, no further processing will occur and no further interceptors will be called. - * @throws AuthenticationException - * This exception may be thrown to indicate that the interceptor has detected an unauthorized access attempt. If thrown, processing will stop and an HTTP 401 will be returned to the - * client. - */ - boolean outgoingResponse(RequestDetails theRequest, Bundle bundle); /** - * This method is called after the server implementation method has been called, but before any attempt to stream the response back to the client + * This method is called after the server implementation method has been called, but before any attempt to stream the + * response back to the client * * @param theRequestDetails - * A bean containing details about the request that is about to be processed, including details such as the resource type and logical ID (if any) and other FHIR-specific aspects of the - * request which have been pulled out of the {@link HttpServletRequest servlet request}. + * A bean containing details about the request that is about to be processed, including + * @param theResponseObject + * The actual object which is being streamed to the client as a response * @param theServletRequest * The incoming request * @param theServletResponse - * The response. Note that interceptors may choose to provide a response (i.e. by calling {@link HttpServletResponse#getWriter()}) but in that case it is important to return - * false to indicate that the server itself should not also provide a response. - * @return Return true if processing should continue normally. This is generally the right thing to do. If your interceptor is providing a response rather than letting HAPI handle the - * response normally, you must return false. In this case, no further processing will occur and no further interceptors will be called. + * The response. Note that interceptors may choose to provide a response (i.e. by calling + * {@link HttpServletResponse#getWriter()}) but in that case it is important to return false + * to indicate that the server itself should not also provide a response. + * @return Return true if processing should continue normally. This is generally the right thing to do. + * If your interceptor is providing a response rather than letting HAPI handle the response normally, you + * must return false. In this case, no further processing will occur and no further interceptors + * will be called. * @throws AuthenticationException - * This exception may be thrown to indicate that the interceptor has detected an unauthorized access attempt. If thrown, processing will stop and an HTTP 401 will be returned to the - * client. + * This exception may be thrown to indicate that the interceptor has detected an unauthorized access + * attempt. If thrown, processing will stop and an HTTP 401 will be returned to the client. + */ + boolean outgoingResponse(RequestDetails theRequest, Bundle bundle); + + /** + * This method is called after the server implementation method has been called, but before any attempt to stream the + * response back to the client + * + * @param theRequestDetails + * A bean containing details about the request that is about to be processed, including details such as the + * resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been + * pulled out of the {@link HttpServletRequest servlet request}. + * @param theServletRequest + * The incoming request + * @param theServletResponse + * The response. Note that interceptors may choose to provide a response (i.e. by calling + * {@link HttpServletResponse#getWriter()}) but in that case it is important to return false + * to indicate that the server itself should not also provide a response. + * @return Return true if processing should continue normally. This is generally the right thing to do. + * If your interceptor is providing a response rather than letting HAPI handle the response normally, you + * must return false. In this case, no further processing will occur and no further interceptors + * will be called. + * @throws AuthenticationException + * This exception may be thrown to indicate that the interceptor has detected an unauthorized access + * attempt. If thrown, processing will stop and an HTTP 401 will be returned to the client. */ boolean outgoingResponse(RequestDetails theRequestDetails, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws AuthenticationException; - - /** - * This method is called after the server implementation method has been called, but before any attempt to stream the response back to the client - * - * @param theRequestDetails - * A bean containing details about the request that is about to be processed, including details such as the resource type and logical ID (if any) and other FHIR-specific aspects of the - * request which have been pulled out of the {@link HttpServletRequest servlet request}. - * @return Return true if processing should continue normally. This is generally the right thing to do. If your interceptor is providing a response rather than letting HAPI handle the - * response normally, you must return false. In this case, no further processing will occur and no further interceptors will be called. - * @throws AuthenticationException - * This exception may be thrown to indicate that the interceptor has detected an unauthorized access attempt. If thrown, processing will stop and an HTTP 401 will be returned to the - * client. - */ - boolean outgoingResponse(RequestDetails theRequestDetails); /** - * This method is called after the server implementation method has been called, but before any attempt to stream the response back to the client + * This method is called after the server implementation method has been called, but before any attempt to stream the + * response back to the client * * @param theRequestDetails - * A bean containing details about the request that is about to be processed, including details such as the resource type and logical ID (if any) and other FHIR-specific aspects of the - * request which have been pulled out of the {@link HttpServletRequest servlet request}. - * @param theResponseObject - * The actual object which is being streamed to the client as a response - * @param theServletRequest - * The incoming request - * @param theServletResponse - * The response. Note that interceptors may choose to provide a response (i.e. by calling {@link HttpServletResponse#getWriter()}) but in that case it is important to return - * false to indicate that the server itself should not also provide a response. - * @return Return true if processing should continue normally. This is generally the right thing to do. If your interceptor is providing a response rather than letting HAPI handle the - * response normally, you must return false. In this case, no further processing will occur and no further interceptors will be called. + * A bean containing details about the request that is about to be processed, including details such as the + * resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been + * pulled out of the {@link HttpServletRequest servlet request}. + * @return Return true if processing should continue normally. This is generally the right thing to do. + * If your interceptor is providing a response rather than letting HAPI handle the response normally, you + * must return false. In this case, no further processing will occur and no further interceptors + * will be called. * @throws AuthenticationException - * This exception may be thrown to indicate that the interceptor has detected an unauthorized access attempt. If thrown, processing will stop and an HTTP 401 will be returned to the - * client. + * This exception may be thrown to indicate that the interceptor has detected an unauthorized access + * attempt. If thrown, processing will stop and an HTTP 401 will be returned to the client. */ - boolean outgoingResponse(RequestDetails theRequestDetails, IBaseResource theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) - throws AuthenticationException; - - /** - * This method is called after the server implementation method has been called, but before any attempt to stream the response back to the client - * - * @param theRequestDetails - * A bean containing details about the request that is about to be processed, including details such as the resource type and logical ID (if any) and other FHIR-specific aspects of the - * request which have been pulled out of the {@link HttpServletRequest servlet request}. - * @param theResponseObject - * The actual object which is being streamed to the client as a response - * @return Return true if processing should continue normally. This is generally the right thing to do. If your interceptor is providing a response rather than letting HAPI handle the - * response normally, you must return false. In this case, no further processing will occur and no further interceptors will be called. - * @throws AuthenticationException - * This exception may be thrown to indicate that the interceptor has detected an unauthorized access attempt. If thrown, processing will stop and an HTTP 401 will be returned to the - * client. - */ - boolean outgoingResponse(RequestDetails theRequestDetails, IBaseResource theResponseObject); + boolean outgoingResponse(RequestDetails theRequestDetails); /** - * This method is called after the server implementation method has been called, but before any attempt to stream the response back to the client + * This method is called after the server implementation method has been called, but before any attempt to stream the + * response back to the client * * @param theRequestDetails - * A bean containing details about the request that is about to be processed, including details such as the resource type and logical ID (if any) and other FHIR-specific aspects of the - * request which have been pulled out of the {@link HttpServletRequest servlet request}. + * A bean containing details about the request that is about to be processed, including details such as the + * resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been + * pulled out of the {@link HttpServletRequest servlet request}. * @param theResponseObject * The actual object which is being streamed to the client as a response * @param theServletRequest * The incoming request * @param theServletResponse - * The response. Note that interceptors may choose to provide a response (i.e. by calling {@link HttpServletResponse#getWriter()}) but in that case it is important to return - * false to indicate that the server itself should not also provide a response. - * @return Return true if processing should continue normally. This is generally the right thing to do. If your interceptor is providing a response rather than letting HAPI handle the - * response normally, you must return false. In this case, no further processing will occur and no further interceptors will be called. + * The response. Note that interceptors may choose to provide a response (i.e. by calling + * {@link HttpServletResponse#getWriter()}) but in that case it is important to return false + * to indicate that the server itself should not also provide a response. + * @return Return true if processing should continue normally. This is generally the right thing to do. + * If your interceptor is providing a response rather than letting HAPI handle the response normally, you + * must return false. In this case, no further processing will occur and no further interceptors + * will be called. * @throws AuthenticationException - * This exception may be thrown to indicate that the interceptor has detected an unauthorized access attempt. If thrown, processing will stop and an HTTP 401 will be returned to the - * client. + * This exception may be thrown to indicate that the interceptor has detected an unauthorized access + * attempt. If thrown, processing will stop and an HTTP 401 will be returned to the client. + */ + boolean outgoingResponse(RequestDetails theRequestDetails, IBaseResource theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws AuthenticationException; + + /** + * This method is called after the server implementation method has been called, but before any attempt to stream the + * response back to the client + * + * @param theRequestDetails + * A bean containing details about the request that is about to be processed, including details such as the + * resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been + * pulled out of the {@link HttpServletRequest servlet request}. + * @param theResponseObject + * The actual object which is being streamed to the client as a response + * @return Return true if processing should continue normally. This is generally the right thing to do. + * If your interceptor is providing a response rather than letting HAPI handle the response normally, you + * must return false. In this case, no further processing will occur and no further interceptors + * will be called. + * @throws AuthenticationException + * This exception may be thrown to indicate that the interceptor has detected an unauthorized access + * attempt. If thrown, processing will stop and an HTTP 401 will be returned to the client. + */ + boolean outgoingResponse(RequestDetails theRequestDetails, IBaseResource theResponseObject); + + /** + * This method is called after the server implementation method has been called, but before any attempt to stream the + * response back to the client + * + * @param theRequestDetails + * A bean containing details about the request that is about to be processed, including details such as the + * resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been + * pulled out of the {@link HttpServletRequest servlet request}. + * @param theResponseObject + * The actual object which is being streamed to the client as a response + * @param theServletRequest + * The incoming request + * @param theServletResponse + * The response. Note that interceptors may choose to provide a response (i.e. by calling + * {@link HttpServletResponse#getWriter()}) but in that case it is important to return false + * to indicate that the server itself should not also provide a response. + * @return Return true if processing should continue normally. This is generally the right thing to do. + * If your interceptor is providing a response rather than letting HAPI handle the response normally, you + * must return false. In this case, no further processing will occur and no further interceptors + * will be called. + * @throws AuthenticationException + * This exception may be thrown to indicate that the interceptor has detected an unauthorized access + * attempt. If thrown, processing will stop and an HTTP 401 will be returned to the client. */ boolean outgoingResponse(RequestDetails theRequestDetails, TagList theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws AuthenticationException; - /** - * This method is called after the server implementation method has been called, but before any attempt to stream the response back to the client - * - * @param theRequestDetails - * A bean containing details about the request that is about to be processed, including details such as the resource type and logical ID (if any) and other FHIR-specific aspects of the - * request which have been pulled out of the {@link HttpServletRequest servlet request}. - * @param theResponseObject - * The actual object which is being streamed to the client as a response - * @return Return true if processing should continue normally. This is generally the right thing to do. If your interceptor is providing a response rather than letting HAPI handle the - * response normally, you must return false. In this case, no further processing will occur and no further interceptors will be called. - * @throws AuthenticationException - * This exception may be thrown to indicate that the interceptor has detected an unauthorized access attempt. If thrown, processing will stop and an HTTP 401 will be returned to the - * client. - */ - boolean outgoingResponse(RequestDetails theRequestDetails, TagList theResponseObject); + /** + * This method is called after the server implementation method has been called, but before any attempt to stream the + * response back to the client + * + * @param theRequestDetails + * A bean containing details about the request that is about to be processed, including details such as the + * resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been + * pulled out of the {@link HttpServletRequest servlet request}. + * @param theResponseObject + * The actual object which is being streamed to the client as a response + * @return Return true if processing should continue normally. This is generally the right thing to do. + * If your interceptor is providing a response rather than letting HAPI handle the response normally, you + * must return false. In this case, no further processing will occur and no further interceptors + * will be called. + * @throws AuthenticationException + * This exception may be thrown to indicate that the interceptor has detected an unauthorized access + * attempt. If thrown, processing will stop and an HTTP 401 will be returned to the client. + */ + boolean outgoingResponse(RequestDetails theRequestDetails, TagList theResponseObject); /** - * This method is called upon any exception being thrown within the server's request processing code. This includes any exceptions thrown within resource provider methods (e.g. {@link Search} and - * {@link Read} methods) as well as any runtime exceptions thrown by the server itself. This method is invoked for each interceptor (until one of them returns a non-null response or - * the end of the list is reached), after which {@link #handleException(RequestDetails, BaseServerResponseException, HttpServletRequest, HttpServletResponse)} is called for each interceptor. + * This method is called upon any exception being thrown within the server's request processing code. This includes + * any exceptions thrown within resource provider methods (e.g. {@link Search} and {@link Read} methods) as well as + * any runtime exceptions thrown by the server itself. This method is invoked for each interceptor (until one of them + * returns a non-null response or the end of the list is reached), after which + * {@link #handleException(RequestDetails, BaseServerResponseException, HttpServletRequest, HttpServletResponse)} is + * called for each interceptor. *

* This may be used to add an OperationOutcome to a response, or to convert between exception types for any reason. *

*

- * Implementations of this method may choose to ignore/log/count/etc exceptions, and return null. In this case, processing will continue, and the server will automatically generate an - * {@link BaseOperationOutcome OperationOutcome}. Implementations may also choose to provide their own response to the client. In this case, they should return a non-null, to indicate - * that they have handled the request and processing should stop. + * Implementations of this method may choose to ignore/log/count/etc exceptions, and return null. In + * this case, processing will continue, and the server will automatically generate an {@link BaseOperationOutcome + * OperationOutcome}. Implementations may also choose to provide their own response to the client. In this case, they + * should return a non-null, to indicate that they have handled the request and processing should stop. *

* - * @return Returns the new exception to use for processing, or null if this interceptor is not trying to modify the exception. For example, if this interceptor has nothing to do with - * exception processing, it should always return null. If this interceptor adds an OperationOutcome to the exception, it should return an exception. + * @return Returns the new exception to use for processing, or null if this interceptor is not trying to + * modify the exception. For example, if this interceptor has nothing to do with exception processing, it + * should always return null. If this interceptor adds an OperationOutcome to the exception, it + * should return an exception. */ BaseServerResponseException preProcessOutgoingException(RequestDetails theRequestDetails, Throwable theException, HttpServletRequest theServletRequest) throws ServletException; @@ -300,19 +357,26 @@ public interface IServerInterceptor { private boolean myLocked = false; private IBaseResource myResource; private final String myResourceType; + private final FhirContext myContext; - public ActionRequestDetails(IIdType theId, String theResourceType) { + public ActionRequestDetails(IIdType theId, String theResourceType, FhirContext theContext) { myId = theId; myResourceType = theResourceType; + myContext = theContext; } public ActionRequestDetails(RequestDetails theRequestDetails) { myId = theRequestDetails.getId(); myResourceType = theRequestDetails.getResourceName(); + myContext = theRequestDetails.getServer().getFhirContext(); } - public ActionRequestDetails(IIdType theId, String theResourceType, IBaseResource theResource) { - this(theId, theResourceType); + public FhirContext getContext() { + return myContext; + } + + public ActionRequestDetails(IIdType theId, String theResourceType, IBaseResource theResource, FhirContext theContext) { + this(theId, theResourceType, theContext); myResource = theResource; } @@ -324,10 +388,12 @@ public interface IServerInterceptor { } /** - * For requests where a resource is passed from the client to the server (e.g. create, update, etc.) this method will return the resource which was provided by the client. Otherwise, this method - * will return null. + * For requests where a resource is passed from the client to the server (e.g. create, update, etc.) this method + * will return the resource which was provided by the client. Otherwise, this method will return null + * . *

- * Note that this method is currently only populated if the handling method has a parameter annotated with the {@link ResourceParam} annotation. + * Note that this method is currently only populated if the handling method has a parameter annotated with the + * {@link ResourceParam} annotation. *

*/ public IBaseResource getResource() { @@ -335,7 +401,8 @@ public interface IServerInterceptor { } /** - * Returns the resource type this request pertains to, or null if this request is not type specific (e.g. server-history) + * Returns the resource type this request pertains to, or null if this request is not type specific + * (e.g. server-history) */ public String getResourceType() { return myResourceType; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/RequestValidatingInterceptor.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/RequestValidatingInterceptor.java new file mode 100644 index 00000000000..1906ef5f41f --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/RequestValidatingInterceptor.java @@ -0,0 +1,71 @@ +package ca.uhn.fhir.rest.server.interceptor; + +import java.nio.charset.Charset; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import ca.uhn.fhir.rest.method.RequestDetails; +import ca.uhn.fhir.rest.param.ResourceParameter; +import ca.uhn.fhir.rest.server.EncodingEnum; +import ca.uhn.fhir.rest.server.RestfulServerUtils; +import ca.uhn.fhir.rest.server.exceptions.AuthenticationException; +import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; +import ca.uhn.fhir.validation.FhirValidator; +import ca.uhn.fhir.validation.ResultSeverityEnum; +import ca.uhn.fhir.validation.ValidationResult; + +/** + * This interceptor intercepts each incoming request and if it contains a FHIR resource, validates that resource. The + * interceptor may be configured to run any validator modules, and will then add headers to the response or fail the + * request with an {@link UnprocessableEntityException HTTP 422 Unprocessable Entity}. + */ +public class RequestValidatingInterceptor extends BaseValidatingInterceptor { + + /** + * X-HAPI-Request-Validation + */ + public static final String DEFAULT_RESPONSE_HEADER_NAME = "X-HAPI-Request-Validation"; + + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RequestValidatingInterceptor.class); + + @Override + public boolean incomingRequestPostProcessed(RequestDetails theRequestDetails, HttpServletRequest theRequest, HttpServletResponse theResponse) throws AuthenticationException { + EncodingEnum encoding = RestfulServerUtils.determineRequestEncodingNoDefault(theRequestDetails); + if (encoding == null) { + ourLog.trace("Incoming request does not appear to be FHIR, not going to validate"); + return true; + } + + Charset charset = ResourceParameter.determineRequestCharset(theRequestDetails); + String requestText = new String(theRequestDetails.loadRequestContents(), charset); + validate(requestText, theRequestDetails); + + return true; + } + + + /** + * Sets the name of the response header to add validation failures to + * + * @see #DEFAULT_RESPONSE_HEADER_NAME + * @see #setAddResponseHeaderOnSeverity(ResultSeverityEnum) + */ + @Override + public void setResponseHeaderName(String theResponseHeaderName) { + super.setResponseHeaderName(theResponseHeaderName); + } + + + @Override + String provideDefaultResponseHeaderName() { + return DEFAULT_RESPONSE_HEADER_NAME; + } + + + @Override + ValidationResult doValidate(FhirValidator theValidator, String theRequest) { + return theValidator.validateWithResult(theRequest); + } + +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/ResponseValidatingInterceptor.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/ResponseValidatingInterceptor.java index 6234c6af83a..6fc48753f1b 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/ResponseValidatingInterceptor.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/ResponseValidatingInterceptor.java @@ -1,5 +1,7 @@ package ca.uhn.fhir.rest.server.interceptor; +import java.nio.charset.Charset; + /* * #%L * HAPI FHIR - Core Library @@ -29,49 +31,54 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.rest.method.RequestDetails; +import ca.uhn.fhir.rest.param.ResourceParameter; +import ca.uhn.fhir.rest.server.EncodingEnum; +import ca.uhn.fhir.rest.server.RestfulServerUtils; import ca.uhn.fhir.rest.server.exceptions.AuthenticationException; +import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import ca.uhn.fhir.validation.FhirValidator; +import ca.uhn.fhir.validation.ResultSeverityEnum; +import ca.uhn.fhir.validation.ValidationResult; /** - * Not yet complete! - * - * TODO: complete this + * This interceptor intercepts each outgoing response and if it contains a FHIR resource, validates that resource. The + * interceptor may be configured to run any validator modules, and will then add headers to the response or fail the + * request with an {@link UnprocessableEntityException HTTP 422 Unprocessable Entity}. */ -class ResponseValidatingInterceptor extends InterceptorAdapter { +public class ResponseValidatingInterceptor extends BaseValidatingInterceptor { - private FhirValidator myValidator; - /** - * Returns the validator used by this interceptor + * X-HAPI-Request-Validation */ - public FhirValidator getValidator() { - return myValidator; + public static final String DEFAULT_RESPONSE_HEADER_NAME = "X-HAPI-Response-Validation"; + + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResponseValidatingInterceptor.class); + + @Override + public boolean outgoingResponse(RequestDetails theRequestDetails, IBaseResource theResponseObject) { + validate(theResponseObject, theRequestDetails); + return true; } /** - * Sets the validator instance to use. Must not be null. + * Sets the name of the response header to add validation failures to + * + * @see #DEFAULT_RESPONSE_HEADER_NAME + * @see #setAddResponseHeaderOnSeverity(ResultSeverityEnum) */ - public void setValidator(FhirValidator theValidator) { - Validate.notNull(theValidator, "Validator must not be null"); - myValidator = theValidator; + @Override + public void setResponseHeaderName(String theResponseHeaderName) { + super.setResponseHeaderName(theResponseHeaderName); } @Override - public boolean outgoingResponse(RequestDetails theRequestDetails, TagList theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws AuthenticationException { - return true; + String provideDefaultResponseHeaderName() { + return DEFAULT_RESPONSE_HEADER_NAME; } @Override - public boolean outgoingResponse(RequestDetails theRequestDetails, Bundle theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws AuthenticationException { - return true; + ValidationResult doValidate(FhirValidator theValidator, IBaseResource theRequest) { + return theValidator.validateWithResult(theRequest); } - @Override - public boolean outgoingResponse(RequestDetails theRequestDetails, IBaseResource theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws AuthenticationException { - - return true; - } - - - } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/servlet/ServletRestfulResponse.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/servlet/ServletRestfulResponse.java index c5fecb39235..02d02d0aabc 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/servlet/ServletRestfulResponse.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/servlet/ServletRestfulResponse.java @@ -38,60 +38,60 @@ import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.RestfulResponse; public class ServletRestfulResponse extends RestfulResponse { - - public ServletRestfulResponse(ServletRequestDetails servletRequestDetails) { - super(servletRequestDetails); - } - - @Override - public Object sendAttachmentResponse(IBaseBinary bin, int stausCode, String contentType) throws IOException { - addHeaders(); - HttpServletResponse theHttpResponse = getRequestDetails().getServletResponse(); - theHttpResponse.setStatus(stausCode); - theHttpResponse.setContentType(contentType); - if (bin.getContent() == null || bin.getContent().length == 0) { - return null; - } else { - theHttpResponse.setContentLength(bin.getContent().length); - ServletOutputStream oos = theHttpResponse.getOutputStream(); - oos.write(bin.getContent()); - oos.close(); - return null; - } - } - @Override - public Writer getResponseWriter(int statusCode, String contentType, String charset, boolean theRespondGzip) throws UnsupportedEncodingException, IOException { - addHeaders(); - HttpServletResponse theHttpResponse = getRequestDetails().getServletResponse(); - theHttpResponse.setCharacterEncoding(charset); - theHttpResponse.setStatus(statusCode); - theHttpResponse.setContentType(contentType); + public ServletRestfulResponse(ServletRequestDetails servletRequestDetails) { + super(servletRequestDetails); + } + + @Override + public Object sendAttachmentResponse(IBaseBinary bin, int stausCode, String contentType) throws IOException { + addHeaders(); + HttpServletResponse theHttpResponse = getRequestDetails().getServletResponse(); + theHttpResponse.setStatus(stausCode); + theHttpResponse.setContentType(contentType); + if (bin.getContent() == null || bin.getContent().length == 0) { + return null; + } else { + theHttpResponse.setContentLength(bin.getContent().length); + ServletOutputStream oos = theHttpResponse.getOutputStream(); + oos.write(bin.getContent()); + oos.close(); + return null; + } + } + + @Override + public Writer getResponseWriter(int statusCode, String contentType, String charset, boolean theRespondGzip) throws UnsupportedEncodingException, IOException { + addHeaders(); + HttpServletResponse theHttpResponse = getRequestDetails().getServletResponse(); + theHttpResponse.setCharacterEncoding(charset); + theHttpResponse.setStatus(statusCode); + theHttpResponse.setContentType(contentType); if (theRespondGzip) { theHttpResponse.addHeader(Constants.HEADER_CONTENT_ENCODING, Constants.ENCODING_GZIP); return new OutputStreamWriter(new GZIPOutputStream(theHttpResponse.getOutputStream()), Constants.CHARSET_NAME_UTF8); } else { return theHttpResponse.getWriter(); } - } + } + private void addHeaders() { + HttpServletResponse theHttpResponse = getRequestDetails().getServletResponse(); + getRequestDetails().getServer().addHeadersToResponse(theHttpResponse); + for (Entry header : getHeaders().entrySet()) { + theHttpResponse.setHeader(header.getKey(), header.getValue()); + } + } - private void addHeaders() { - HttpServletResponse theHttpResponse = getRequestDetails().getServletResponse(); - getRequestDetails().getServer().addHeadersToResponse(theHttpResponse); - for (Entry header : getHeaders().entrySet()) { - theHttpResponse.setHeader(header.getKey(), header.getValue()); - } - } - + @Override public final Object sendWriterResponse(int status, String contentType, String charset, Writer writer) throws IOException { - writer.close(); - return null; - } + writer.close(); + return null; + } - @Override - public Object returnResponse(ParseAction outcome, int operationStatus, boolean allowPrefer, MethodOutcome response, - String resourceName) throws IOException { - return getRequestDetails().getServer().returnResponse(getRequestDetails(), outcome, operationStatus, allowPrefer, response, resourceName); - } + @Override + public Object returnResponse(ParseAction outcome, int operationStatus, boolean allowPrefer, MethodOutcome response, String resourceName) throws IOException { + addHeaders(); + return getRequestDetails().getServer().returnResponse(getRequestDetails(), outcome, operationStatus, allowPrefer, response, resourceName); + } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseDstu21Config.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseDstu21Config.java index a42e53a923a..e5e568d8119 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseDstu21Config.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseDstu21Config.java @@ -1,5 +1,12 @@ package ca.uhn.fhir.jpa.config; +import org.hl7.fhir.dstu21.hapi.validation.DefaultProfileValidationSupport; +import org.hl7.fhir.dstu21.hapi.validation.FhirInstanceValidator; +import org.hl7.fhir.dstu21.hapi.validation.FhirQuestionnaireResponseValidator; +import org.hl7.fhir.dstu21.hapi.validation.IValidationSupport; +import org.hl7.fhir.dstu21.hapi.validation.ValidationSupportChain; +import org.hl7.fhir.dstu21.validation.IResourceValidator.BestPracticeWarningLevel; + /* * #%L * HAPI FHIR JPA Server @@ -21,8 +28,11 @@ package ca.uhn.fhir.jpa.config; */ import org.springframework.beans.factory.annotation.Autowire; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Primary; import org.springframework.transaction.annotation.EnableTransactionManagement; @@ -30,6 +40,7 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.dao.FhirSearchDao; import ca.uhn.fhir.jpa.dao.IFhirSystemDao; import ca.uhn.fhir.jpa.dao.ISearchDao; +import ca.uhn.fhir.validation.IValidatorModule; @Configuration @EnableTransactionManagement @@ -48,22 +59,48 @@ public class BaseDstu21Config extends BaseConfig { } @Bean(name = "mySystemProviderDstu21") - public ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu21 systemProviderDstu2() { + public ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu21 systemProviderDstu21() { ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu21 retVal = new ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu21(); retVal.setDao(systemDaoDstu21()); return retVal; } @Bean(name = "myJpaValidationSupportDstu21", autowire = Autowire.BY_NAME) - public ca.uhn.fhir.jpa.dao.IJpaValidationSupportDstu21 jpaValidationSupportDstu2() { + public ca.uhn.fhir.jpa.dao.IJpaValidationSupportDstu21 jpaValidationSupportDstu21() { ca.uhn.fhir.jpa.dao.JpaValidationSupportDstu21 retVal = new ca.uhn.fhir.jpa.dao.JpaValidationSupportDstu21(); return retVal; } + @Qualifier("myJpaValidationSupportDstu21") + private IValidationSupport myJpaValidationSupportDstu21; + @Bean(autowire = Autowire.BY_TYPE) - public ISearchDao searchDao() { + public ISearchDao searchDaoDstu21() { FhirSearchDao searchDao = new FhirSearchDao(); return searchDao; } + + @Bean(name="myInstanceValidatorDstu21") + @Lazy + public IValidatorModule instanceValidatorDstu21() { + FhirInstanceValidator val = new FhirInstanceValidator(); + val.setBestPracticeWarningLevel(BestPracticeWarningLevel.Warning); + val.setValidationSupport(validationSupportChainDstu21()); + return val; + } + + @Bean(name="myQuestionnaireResponseValidatorDstu21") + @Lazy + public IValidatorModule questionnaireResponseValidatorDstu21() { + FhirQuestionnaireResponseValidator module = new FhirQuestionnaireResponseValidator(); + module.setValidationSupport(validationSupportChainDstu21()); + return module; + } + + @Bean + public IValidationSupport validationSupportChainDstu21() { + return new ValidationSupportChain(new DefaultProfileValidationSupport(), myJpaValidationSupportDstu21); +// return new ValidationSupportChain(); + } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java index bc0b70e448d..9b41669f4ce 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java @@ -154,26 +154,26 @@ public abstract class BaseHapiFhirResourceDao extends B if (getContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU1)) { if (theResource.getIdElement().isIdPartValidLong()) { String message = getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "failedToCreateWithClientAssignedNumericId", theResource.getIdElement().getIdPart()); - throw new InvalidRequestException(message, createErrorOperationOutcome(message)); + throw new InvalidRequestException(message, createErrorOperationOutcome(message, "processing")); } } else { String message = getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "failedToCreateWithClientAssignedId", theResource.getIdElement().getIdPart()); - throw new InvalidRequestException(message, createErrorOperationOutcome(message)); + throw new InvalidRequestException(message, createErrorOperationOutcome(message, "processing")); } } return doCreate(theResource, theIfNoneExist, thePerformIndexing, new Date()); } - public IBaseOperationOutcome createErrorOperationOutcome(String theMessage) { - return createOperationOutcome(OO_SEVERITY_ERROR, theMessage); + public IBaseOperationOutcome createErrorOperationOutcome(String theMessage, String theCode) { + return createOperationOutcome(OO_SEVERITY_ERROR, theMessage, theCode); } public IBaseOperationOutcome createInfoOperationOutcome(String theMessage) { - return createOperationOutcome(OO_SEVERITY_INFO, theMessage); + return createOperationOutcome(OO_SEVERITY_INFO, theMessage, "informational"); } - protected abstract IBaseOperationOutcome createOperationOutcome(String theSeverity, String theMessage); + protected abstract IBaseOperationOutcome createOperationOutcome(String theSeverity, String theMessage, String theCode); @Override public DaoMethodOutcome delete(IIdType theId) { @@ -201,7 +201,7 @@ public abstract class BaseHapiFhirResourceDao extends B validateOkToDelete(deleteConflicts, entity); // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(theId, theId.getResourceType()); + ActionRequestDetails requestDetails = new ActionRequestDetails(theId, theId.getResourceType(), getContext()); notifyInterceptors(RestOperationTypeEnum.DELETE, requestDetails); Date updateTime = new Date(); @@ -251,7 +251,7 @@ public abstract class BaseHapiFhirResourceDao extends B // Notify interceptors IdDt idToDelete = entity.getIdDt(); - ActionRequestDetails requestDetails = new ActionRequestDetails(idToDelete, idToDelete.getResourceType()); + ActionRequestDetails requestDetails = new ActionRequestDetails(idToDelete, idToDelete.getResourceType(), getContext()); notifyInterceptors(RestOperationTypeEnum.DELETE, requestDetails); // Perform delete @@ -308,7 +308,7 @@ public abstract class BaseHapiFhirResourceDao extends B } // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(theResource.getIdElement(), toResourceName(theResource), theResource); + ActionRequestDetails requestDetails = new ActionRequestDetails(theResource.getIdElement(), toResourceName(theResource), theResource, getContext()); notifyInterceptors(RestOperationTypeEnum.CREATE, requestDetails); // Perform actual DB update @@ -333,7 +333,7 @@ public abstract class BaseHapiFhirResourceDao extends B @Override public TagList getAllResourceTags() { // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(null, null); + ActionRequestDetails requestDetails = new ActionRequestDetails(null, null, getContext()); notifyInterceptors(RestOperationTypeEnum.GET_TAGS, requestDetails); StopWatch w = new StopWatch(); @@ -356,7 +356,7 @@ public abstract class BaseHapiFhirResourceDao extends B @Override public TagList getTags(IIdType theResourceId) { // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(theResourceId, null); + ActionRequestDetails requestDetails = new ActionRequestDetails(theResourceId, null, getContext()); notifyInterceptors(RestOperationTypeEnum.GET_TAGS, requestDetails); StopWatch w = new StopWatch(); @@ -368,7 +368,7 @@ public abstract class BaseHapiFhirResourceDao extends B @Override public IBundleProvider history(Date theSince) { // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(null, null); + ActionRequestDetails requestDetails = new ActionRequestDetails(null, null, getContext()); notifyInterceptors(RestOperationTypeEnum.HISTORY_SYSTEM, requestDetails); StopWatch w = new StopWatch(); @@ -380,7 +380,7 @@ public abstract class BaseHapiFhirResourceDao extends B @Override public IBundleProvider history(final IIdType theId, final Date theSince) { // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(theId, getResourceName()); + ActionRequestDetails requestDetails = new ActionRequestDetails(theId, getResourceName(), getContext()); notifyInterceptors(RestOperationTypeEnum.HISTORY_INSTANCE, requestDetails); final InstantDt end = createHistoryToTimestamp(); @@ -495,7 +495,7 @@ public abstract class BaseHapiFhirResourceDao extends B @Override public IBundleProvider history(Long theId, Date theSince) { // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName()); + ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName(), getContext()); notifyInterceptors(RestOperationTypeEnum.HISTORY_TYPE, requestDetails); StopWatch w = new StopWatch(); @@ -507,7 +507,7 @@ public abstract class BaseHapiFhirResourceDao extends B @Override public MT metaAddOperation(IIdType theResourceId, MT theMetaAdd) { // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(theResourceId, getResourceName()); + ActionRequestDetails requestDetails = new ActionRequestDetails(theResourceId, getResourceName(), getContext()); notifyInterceptors(RestOperationTypeEnum.META_ADD, requestDetails); StopWatch w = new StopWatch(); @@ -634,7 +634,7 @@ public abstract class BaseHapiFhirResourceDao extends B @Override public MT metaDeleteOperation(IIdType theResourceId, MT theMetaDel) { // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(theResourceId, getResourceName()); + ActionRequestDetails requestDetails = new ActionRequestDetails(theResourceId, getResourceName(), getContext()); notifyInterceptors(RestOperationTypeEnum.META_DELETE, requestDetails); StopWatch w = new StopWatch(); @@ -675,7 +675,7 @@ public abstract class BaseHapiFhirResourceDao extends B @Override public MT metaGetOperation(Class theType) { // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName()); + ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName(), getContext()); notifyInterceptors(RestOperationTypeEnum.META, requestDetails); String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t WHERE t.myResourceType = :res_type)"; @@ -714,7 +714,7 @@ public abstract class BaseHapiFhirResourceDao extends B @Override public MT metaGetOperation(Class theType, IIdType theId) { // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(theId, getResourceName()); + ActionRequestDetails requestDetails = new ActionRequestDetails(theId, getResourceName(), getContext()); notifyInterceptors(RestOperationTypeEnum.META, requestDetails); Set tagDefs = new HashSet(); @@ -771,7 +771,7 @@ public abstract class BaseHapiFhirResourceDao extends B validateResourceTypeAndThrowIllegalArgumentException(theId); // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(theId, getResourceName()); + ActionRequestDetails requestDetails = new ActionRequestDetails(theId, getResourceName(), getContext()); RestOperationTypeEnum operationType = theId.hasVersionIdPart() ? RestOperationTypeEnum.VREAD : RestOperationTypeEnum.READ; notifyInterceptors(operationType, requestDetails); @@ -863,7 +863,7 @@ public abstract class BaseHapiFhirResourceDao extends B @Override public void removeTag(IIdType theId, TagTypeEnum theTagType, String theScheme, String theTerm) { // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(theId, getResourceName()); + ActionRequestDetails requestDetails = new ActionRequestDetails(theId, getResourceName(), getContext()); notifyInterceptors(RestOperationTypeEnum.DELETE_TAGS, requestDetails); StopWatch w = new StopWatch(); @@ -904,7 +904,7 @@ public abstract class BaseHapiFhirResourceDao extends B @Override public IBundleProvider search(final SearchParameterMap theParams) { // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName()); + ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName(), getContext()); notifyInterceptors(RestOperationTypeEnum.SEARCH_TYPE, requestDetails); SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this); @@ -1051,7 +1051,7 @@ public abstract class BaseHapiFhirResourceDao extends B } // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(resourceId, getResourceName(), theResource); + ActionRequestDetails requestDetails = new ActionRequestDetails(resourceId, getResourceName(), theResource, getContext()); notifyInterceptors(RestOperationTypeEnum.UPDATE, requestDetails); // Perform update diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirSystemDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirSystemDao.java index 5edff5a8859..e8af7a17f26 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirSystemDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirSystemDao.java @@ -64,7 +64,7 @@ public abstract class BaseHapiFhirSystemDao extends BaseHapiFhirDao extends BaseHapiFhirDao extends BaseHapiFhirDao extends BaseHapiFhirResou } @Override - protected IBaseOperationOutcome createOperationOutcome(String theSeverity, String theMessage) { + protected IBaseOperationOutcome createOperationOutcome(String theSeverity, String theMessage, String theCode) { OperationOutcome oo = new OperationOutcome(); oo.getIssueFirstRep().getSeverityElement().setValue(theSeverity); oo.getIssueFirstRep().getDetailsElement().setValue(theMessage); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2.java index 4cc7edd3603..eaa57260079 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2.java @@ -89,16 +89,17 @@ public class FhirResourceDaoDstu2 extends BaseHapiFhirResou } @Override - protected IBaseOperationOutcome createOperationOutcome(String theSeverity, String theMessage) { + protected IBaseOperationOutcome createOperationOutcome(String theSeverity, String theMessage, String theCode) { OperationOutcome oo = new OperationOutcome(); oo.getIssueFirstRep().getSeverityElement().setValue(theSeverity); oo.getIssueFirstRep().getDiagnosticsElement().setValue(theMessage); + oo.getIssueFirstRep().getCodeElement().setValue(theCode); return oo; } @Override public MethodOutcome validate(T theResource, IIdType theId, String theRawResource, EncodingEnum theEncoding, ValidationModeEnum theMode, String theProfile) { - ActionRequestDetails requestDetails = new ActionRequestDetails(theId, null, theResource); + ActionRequestDetails requestDetails = new ActionRequestDetails(theId, null, theResource, getContext()); notifyInterceptors(RestOperationTypeEnum.VALIDATE, requestDetails); if (theMode == ValidationModeEnum.DELETE) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu21.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu21.java index b4bc00a5daf..a6f4f979f92 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu21.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu21.java @@ -26,13 +26,12 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.hl7.fhir.dstu21.hapi.validation.FhirInstanceValidator; -import org.hl7.fhir.dstu21.hapi.validation.IValidationSupport; +import org.hl7.fhir.dstu21.exceptions.FHIRException; import org.hl7.fhir.dstu21.model.IdType; import org.hl7.fhir.dstu21.model.OperationOutcome; import org.hl7.fhir.dstu21.model.OperationOutcome.IssueSeverity; import org.hl7.fhir.dstu21.model.OperationOutcome.OperationOutcomeIssueComponent; -import org.hl7.fhir.dstu21.validation.IResourceValidator.BestPracticeWarningLevel; +import org.hl7.fhir.instance.model.OperationOutcome.IssueType; import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IBaseOperationOutcome; import org.hl7.fhir.instance.model.api.IBaseResource; @@ -63,11 +62,26 @@ import ca.uhn.fhir.validation.ValidationResult; public class FhirResourceDaoDstu21 extends BaseHapiFhirResourceDao { - @Autowired() - @Qualifier("myJpaValidationSupportDstu21") - private IValidationSupport myJpaValidationSupport; + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu21.class); + + @Autowired() + @Qualifier("myInstanceValidatorDstu21") + private IValidatorModule myInstanceValidator; + + @Override + protected IBaseOperationOutcome createOperationOutcome(String theSeverity, String theMessage, String theCode) { + OperationOutcome oo = new OperationOutcome(); + OperationOutcomeIssueComponent issue = oo.addIssue(); + issue.getSeverityElement().setValueAsString(theSeverity); + issue.setDiagnostics(theMessage); + try { + issue.setCode(org.hl7.fhir.dstu21.model.OperationOutcome.IssueType.fromCode(theCode)); + } catch (FHIRException e) { + ourLog.error("Unknown code: {}", theCode); + } + return oo; + } - @Override protected List getIncludeValues(FhirTerser theTerser, Include theInclude, IBaseResource theResource, RuntimeResourceDefinition theResourceDef) { List values; @@ -86,18 +100,9 @@ public class FhirResourceDaoDstu21 extends BaseHapiFhirR return values; } - @Override - protected IBaseOperationOutcome createOperationOutcome(String theSeverity, String theMessage) { - OperationOutcome oo = new OperationOutcome(); - OperationOutcomeIssueComponent issue = oo.addIssue(); - issue.getSeverityElement().setValueAsString(theSeverity); - issue.setDiagnostics(theMessage); - return oo; - } - @Override public MethodOutcome validate(T theResource, IIdType theId, String theRawResource, EncodingEnum theEncoding, ValidationModeEnum theMode, String theProfile) { - ActionRequestDetails requestDetails = new ActionRequestDetails(theId, null, theResource); + ActionRequestDetails requestDetails = new ActionRequestDetails(theId, null, theResource, getContext()); notifyInterceptors(RestOperationTypeEnum.VALIDATE, requestDetails); if (theMode == ValidationModeEnum.DELETE) { @@ -111,7 +116,7 @@ public class FhirResourceDaoDstu21 extends BaseHapiFhirR List deleteConflicts = new ArrayList(); validateOkToDelete(deleteConflicts, entity); validateDeleteConflictsEmptyOrThrowException(deleteConflicts); - + OperationOutcome oo = new OperationOutcome(); oo.addIssue().setSeverity(IssueSeverity.INFORMATION).setDiagnostics("Ok to delete"); return new MethodOutcome(new IdType(theId.getValue()), oo); @@ -119,10 +124,7 @@ public class FhirResourceDaoDstu21 extends BaseHapiFhirR FhirValidator validator = getContext().newValidator(); - FhirInstanceValidator val = new FhirInstanceValidator(); - val.setBestPracticeWarningLevel(BestPracticeWarningLevel.Warning); -// val.setValidationSupport(new ValidationSupportChain(new DefaultProfileValidationSupport(), myJpaValidationSupport)); - validator.registerValidatorModule(val); + validator.registerValidatorModule(myInstanceValidator); validator.registerValidatorModule(new IdChecker(theMode)); @@ -151,6 +153,12 @@ public class FhirResourceDaoDstu21 extends BaseHapiFhirR myMode = theMode; } + @CoverageIgnore + @Override + public void validateBundle(IValidationContext theContext) { + throw new UnsupportedOperationException(); + } + @Override public void validateResource(IValidationContext theCtx) { boolean hasId = theCtx.getResource().getIdElement().hasIdPart(); @@ -166,12 +174,6 @@ public class FhirResourceDaoDstu21 extends BaseHapiFhirR } - @CoverageIgnore - @Override - public void validateBundle(IValidationContext theContext) { - throw new UnsupportedOperationException(); - } - } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoPatientDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoPatientDstu2.java index 711cd5eebb8..bed3a16dfdc 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoPatientDstu2.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoPatientDstu2.java @@ -68,7 +68,7 @@ public class FhirResourceDaoPatientDstu2 extends FhirResourceDaoDstu2im @Override public IBundleProvider patientInstanceEverything(HttpServletRequest theServletRequest, IIdType theId, IPrimitiveType theCount, DateRangeParam theLastUpdated, SortSpec theSort, StringAndListParam theContent, StringAndListParam theNarrative) { // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName()); + ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName(), getContext()); notifyInterceptors(RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE, requestDetails); return doEverythingOperation(theId, theCount, theLastUpdated, theSort, theContent, theNarrative); @@ -77,7 +77,7 @@ public class FhirResourceDaoPatientDstu2 extends FhirResourceDaoDstu2im @Override public IBundleProvider patientTypeEverything(HttpServletRequest theServletRequest, IPrimitiveType theCount, DateRangeParam theLastUpdated, SortSpec theSort, StringAndListParam theContent, StringAndListParam theNarrative) { // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName()); + ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName(), getContext()); notifyInterceptors(RestOperationTypeEnum.EXTENDED_OPERATION_TYPE, requestDetails); return doEverythingOperation(null, theCount, theLastUpdated, theSort, theContent, theNarrative); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoPatientDstu21.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoPatientDstu21.java index 1bc01c21a1b..0e37c82cac1 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoPatientDstu21.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoPatientDstu21.java @@ -68,7 +68,7 @@ public class FhirResourceDaoPatientDstu21 extends FhirResourceDaoDstu21 @Override public IBundleProvider patientInstanceEverything(HttpServletRequest theServletRequest, IIdType theId, IPrimitiveType theCount, DateRangeParam theLastUpdated, SortSpec theSort, StringAndListParam theContent, StringAndListParam theNarrative) { // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName()); + ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName(), getContext()); notifyInterceptors(RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE, requestDetails); return doEverythingOperation(theId, theCount, theLastUpdated, theSort, theContent, theNarrative); @@ -77,7 +77,7 @@ public class FhirResourceDaoPatientDstu21 extends FhirResourceDaoDstu21 @Override public IBundleProvider patientTypeEverything(HttpServletRequest theServletRequest, IPrimitiveType theCount, DateRangeParam theLastUpdated, SortSpec theSort, StringAndListParam theContent, StringAndListParam theNarrative) { // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName()); + ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName(), getContext()); notifyInterceptors(RestOperationTypeEnum.EXTENDED_OPERATION_TYPE, requestDetails); return doEverythingOperation(null, theCount, theLastUpdated, theSort, theContent, theNarrative); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoQuestionnaireResponseDstu21.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoQuestionnaireResponseDstu21.java index 15c34867d0c..0d67428c067 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoQuestionnaireResponseDstu21.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoQuestionnaireResponseDstu21.java @@ -22,7 +22,6 @@ package ca.uhn.fhir.jpa.dao; import javax.annotation.PostConstruct; -import org.hl7.fhir.dstu21.hapi.validation.FhirQuestionnaireResponseValidator; import org.hl7.fhir.dstu21.model.OperationOutcome; import org.hl7.fhir.dstu21.model.Questionnaire; import org.hl7.fhir.dstu21.model.QuestionnaireResponse; @@ -31,20 +30,24 @@ import org.hl7.fhir.instance.model.api.IBaseOperationOutcome; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import ca.uhn.fhir.jpa.entity.ResourceTable; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.IResourceLoader; +import ca.uhn.fhir.validation.IValidatorModule; import ca.uhn.fhir.validation.ValidationResult; public class FhirResourceDaoQuestionnaireResponseDstu21 extends FhirResourceDaoDstu21 { private Boolean myValidateResponses; - + @Autowired - private IJpaValidationSupportDstu21 myValidationSupport; + @Qualifier("myQuestionnaireResponseValidatorDstu21") + private IValidatorModule myQuestionnaireResponseValidatorDstu21; + /** * Initialize the bean @@ -75,9 +78,7 @@ public class FhirResourceDaoQuestionnaireResponseDstu21 extends FhirResourceDaoD val.setValidateAgainstStandardSchema(false); val.setValidateAgainstStandardSchematron(false); - FhirQuestionnaireResponseValidator module = new FhirQuestionnaireResponseValidator(); - module.setValidationSupport(myValidationSupport); - val.registerValidatorModule(module); + val.registerValidatorModule(myQuestionnaireResponseValidatorDstu21); ValidationResult result = val.validateWithResult(getContext().newJsonParser().parseResource(getContext().newJsonParser().encodeResourceToString(qa))); if (!result.isSuccessful()) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu1.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu1.java index 7e2f5c4fee0..168902b7899 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu1.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu1.java @@ -64,7 +64,7 @@ public class FhirSystemDaoDstu1 extends BaseHapiFhirSystemDao, M ourLog.info("Beginning transaction with {} resources", theResources.size()); // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(null, null); + ActionRequestDetails requestDetails = new ActionRequestDetails(null, null, getContext()); notifyInterceptors(RestOperationTypeEnum.TRANSACTION, requestDetails); long start = System.currentTimeMillis(); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java index 2053216d2ef..fe68913b34e 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java @@ -200,7 +200,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { @Override public MetaDt metaGetOperation() { // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(null, null); + ActionRequestDetails requestDetails = new ActionRequestDetails(null, null, getContext()); notifyInterceptors(RestOperationTypeEnum.META, requestDetails); String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t)"; @@ -259,7 +259,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao { @Transactional(propagation = Propagation.REQUIRED) @Override public Bundle transaction(RequestDetails theRequestDetails, Bundle theRequest) { - ActionRequestDetails requestDetails = new ActionRequestDetails(null, "Bundle", theRequest); + ActionRequestDetails requestDetails = new ActionRequestDetails(null, "Bundle", theRequest, getContext()); notifyInterceptors(RestOperationTypeEnum.TRANSACTION, requestDetails); String actionName = "Transaction"; diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu21.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu21.java index 8ee4d32745a..1ef7c71a753 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu21.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu21.java @@ -201,7 +201,7 @@ public class FhirSystemDaoDstu21 extends BaseHapiFhirSystemDao { @Override public Meta metaGetOperation() { // Notify interceptors - ActionRequestDetails requestDetails = new ActionRequestDetails(null, null); + ActionRequestDetails requestDetails = new ActionRequestDetails(null, null, getContext()); notifyInterceptors(RestOperationTypeEnum.META, requestDetails); String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t)"; @@ -260,7 +260,7 @@ public class FhirSystemDaoDstu21 extends BaseHapiFhirSystemDao { @Transactional(propagation = Propagation.REQUIRED) @Override public Bundle transaction(RequestDetails theRequestDetails, Bundle theRequest) { - ActionRequestDetails requestDetails = new ActionRequestDetails(null, "Bundle", theRequest); + ActionRequestDetails requestDetails = new ActionRequestDetails(null, "Bundle", theRequest, getContext()); notifyInterceptors(RestOperationTypeEnum.TRANSACTION, requestDetails); String actionName = "Transaction"; diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2Test.java index 24db8682e05..bc6cc8a372c 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2Test.java @@ -74,6 +74,7 @@ import ca.uhn.fhir.model.dstu2.resource.Questionnaire; import ca.uhn.fhir.model.dstu2.valueset.AdministrativeGenderEnum; import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum; import ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum; +import ca.uhn.fhir.model.dstu2.valueset.IssueTypeEnum; import ca.uhn.fhir.model.dstu2.valueset.QuantityComparatorEnum; import ca.uhn.fhir.model.primitive.CodeDt; import ca.uhn.fhir.model.primitive.DateDt; @@ -297,9 +298,10 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test { @Test public void testCreateOperationOutcomeError() { FhirResourceDaoDstu2 dao = new FhirResourceDaoDstu2(); - OperationOutcome oo = (OperationOutcome) dao.createErrorOperationOutcome("my message"); + OperationOutcome oo = (OperationOutcome) dao.createErrorOperationOutcome("my message", "incomplete"); assertEquals(IssueSeverityEnum.ERROR.getCode(), oo.getIssue().get(0).getSeverity()); assertEquals("my message", oo.getIssue().get(0).getDiagnostics()); + assertEquals(IssueTypeEnum.INCOMPLETE_RESULTS, oo.getIssue().get(0).getCodeElement().getValueAsEnum()); } @Test diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu21/BaseJpaDstu21Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu21/BaseJpaDstu21Test.java index 7fda8695b58..4363711fe6f 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu21/BaseJpaDstu21Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu21/BaseJpaDstu21Test.java @@ -83,7 +83,7 @@ import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; //@formatter:off @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes= {TestDstu21Config.class /*, ca.uhn.fhir.jpa.config.WebsocketDstu21Config.class*/ }) +@ContextConfiguration(classes= {TestDstu21Config.class}) //@formatter:on public abstract class BaseJpaDstu21Test extends BaseJpaTest { diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu21/FhirResourceDaoDstu21Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu21/FhirResourceDaoDstu21Test.java index e1cde136d35..4f461cf1b10 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu21/FhirResourceDaoDstu21Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu21/FhirResourceDaoDstu21Test.java @@ -52,6 +52,7 @@ import org.hl7.fhir.dstu21.model.Meta; import org.hl7.fhir.dstu21.model.Observation; import org.hl7.fhir.dstu21.model.OperationOutcome; import org.hl7.fhir.dstu21.model.OperationOutcome.IssueSeverity; +import org.hl7.fhir.dstu21.model.OperationOutcome.IssueType; import org.hl7.fhir.dstu21.model.Organization; import org.hl7.fhir.dstu21.model.Patient; import org.hl7.fhir.dstu21.model.Period; @@ -293,9 +294,10 @@ public class FhirResourceDaoDstu21Test extends BaseJpaDstu21Test { @Test public void testCreateOperationOutcomeError() { FhirResourceDaoDstu21 dao = new FhirResourceDaoDstu21(); - OperationOutcome oo = (OperationOutcome) dao.createErrorOperationOutcome("my message"); + OperationOutcome oo = (OperationOutcome) dao.createErrorOperationOutcome("my message", "incomplete"); assertEquals(IssueSeverity.ERROR.toCode(), oo.getIssue().get(0).getSeverity().toCode()); assertEquals("my message", oo.getIssue().get(0).getDiagnostics()); + assertEquals(IssueType.INCOMPLETE, oo.getIssue().get(0).getCode()); } @Test @@ -304,6 +306,7 @@ public class FhirResourceDaoDstu21Test extends BaseJpaDstu21Test { OperationOutcome oo = (OperationOutcome) dao.createInfoOperationOutcome("my message"); assertEquals(IssueSeverity.INFORMATION.toCode(), oo.getIssue().get(0).getSeverity().toCode()); assertEquals("my message", oo.getIssue().get(0).getDiagnostics()); + assertEquals(IssueType.INFORMATIONAL, oo.getIssue().get(0).getCode()); } @Test diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/TestRestfulServer.java b/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/TestRestfulServer.java index 810a23838c8..61d88094842 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/TestRestfulServer.java +++ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/TestRestfulServer.java @@ -12,6 +12,7 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.web.context.ContextLoaderListener; import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.config.WebsocketDstu21Config; @@ -32,7 +33,10 @@ import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy; import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; +import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor; import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor; +import ca.uhn.fhir.rest.server.interceptor.ResponseValidatingInterceptor; +import ca.uhn.fhir.validation.IValidatorModule; import ca.uhn.fhirtest.config.TestDstu21Config; import ca.uhn.fhirtest.config.TestDstu2Config; @@ -42,7 +46,7 @@ public class TestRestfulServer extends RestfulServer { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TestRestfulServer.class); - private AnnotationConfigApplicationContext myAppCtx; + private AnnotationConfigWebApplicationContext myAppCtx; @SuppressWarnings("unchecked") @Override @@ -72,7 +76,11 @@ public class TestRestfulServer extends RestfulServer { String baseUrlProperty; switch (fhirVersionParam.trim().toUpperCase()) { case "DSTU1": { - myAppCtx = new AnnotationConfigApplicationContext(ca.uhn.fhirtest.config.TestDstu1Config.class); + myAppCtx = new AnnotationConfigWebApplicationContext(); + myAppCtx.setServletConfig(getServletConfig()); + myAppCtx.setParent(parentAppCtx); + myAppCtx.register(ca.uhn.fhirtest.config.TestDstu1Config.class); + myAppCtx.refresh(); setFhirContext(FhirContext.forDstu1()); beans = myAppCtx.getBean("myResourceProvidersDstu1", List.class); systemProviderDstu1 = myAppCtx.getBean("mySystemProviderDstu1", JpaSystemProviderDstu1.class); @@ -85,7 +93,8 @@ public class TestRestfulServer extends RestfulServer { break; } case "DSTU2": { - myAppCtx = new AnnotationConfigApplicationContext(); + myAppCtx = new AnnotationConfigWebApplicationContext(); + myAppCtx.setServletConfig(getServletConfig()); myAppCtx.setParent(parentAppCtx); myAppCtx.register(TestDstu2Config.class, WebsocketDstu2Config.class); myAppCtx.refresh(); @@ -101,7 +110,8 @@ public class TestRestfulServer extends RestfulServer { break; } case "DSTU21": { - myAppCtx = new AnnotationConfigApplicationContext(); + myAppCtx = new AnnotationConfigWebApplicationContext(); + myAppCtx.setServletConfig(getServletConfig()); myAppCtx.setParent(parentAppCtx); myAppCtx.register(TestDstu21Config.class, WebsocketDstu21Config.class); myAppCtx.refresh(); diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/config/TestDstu21Config.java b/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/config/TestDstu21Config.java index d4c3620135e..4184b17a2de 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/config/TestDstu21Config.java +++ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/config/TestDstu21Config.java @@ -9,6 +9,8 @@ import org.apache.commons.dbcp2.BasicDataSource; import org.apache.commons.lang3.time.DateUtils; import org.hibernate.jpa.HibernatePersistenceProvider; import org.springframework.beans.factory.annotation.Autowire; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -23,6 +25,9 @@ import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu21; import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu21; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; +import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor; +import ca.uhn.fhir.rest.server.interceptor.ResponseValidatingInterceptor; +import ca.uhn.fhir.validation.IValidatorModule; @Configuration @Import(CommonConfig.class) @@ -35,13 +40,13 @@ public class TestDstu21Config extends BaseJavaConfigDstu21 { @Value("${fhir.lucene.location.dstu21}") private String myFhirLuceneLocation; - /** - * This lets the "@Value" fields reference properties from the properties file - */ - @Bean - public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { - return new PropertySourcesPlaceholderConfigurer(); - } + @Autowired + @Qualifier("myInstanceValidatorDstu21") + private IValidatorModule myInstanceValidatorDstu21; + + @Autowired + @Qualifier("myQuestionnaireResponseValidatorDstu21") + private IValidatorModule myQuestionnaireResponseValidatorDstu21; @Bean() public DaoConfig daoConfig() { @@ -65,13 +70,6 @@ public class TestDstu21Config extends BaseJavaConfigDstu21 { return retVal; } - @Bean() - public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { - JpaTransactionManager retVal = new JpaTransactionManager(); - retVal.setEntityManagerFactory(entityManagerFactory); - return retVal; - } - @Bean() public LocalContainerEntityManagerFactoryBean entityManagerFactory() { LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean(); @@ -94,16 +92,54 @@ public class TestDstu21Config extends BaseJavaConfigDstu21 { extraProperties.put("hibernate.cache.use_second_level_cache", "false"); extraProperties.put("hibernate.cache.use_structured_entries", "false"); extraProperties.put("hibernate.cache.use_minimal_puts", "false"); - extraProperties.put("hibernate.search.default.directory_provider" ,"filesystem"); + extraProperties.put("hibernate.search.default.directory_provider", "filesystem"); extraProperties.put("hibernate.search.default.indexBase", myFhirLuceneLocation); - extraProperties.put("hibernate.search.lucene_version","LUCENE_CURRENT"); + extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT"); return extraProperties; } - @Bean(autowire=Autowire.BY_TYPE) + /** + * Bean which validates incoming requests + */ + @Bean + public IServerInterceptor requestValidatingInterceptor() { + RequestValidatingInterceptor requestValidator = new RequestValidatingInterceptor(); + requestValidator.addValidatorModule(myInstanceValidatorDstu21); + requestValidator.addValidatorModule(myQuestionnaireResponseValidatorDstu21); + requestValidator.setResponseHeaderValueNoIssues("Validation did not detect any issues"); + return requestValidator; + } + + /** + * Bean which validates outgoing responses + */ + @Bean + public IServerInterceptor responseValidatingInterceptor() { + ResponseValidatingInterceptor responseValidator = new ResponseValidatingInterceptor(); + responseValidator.addValidatorModule(myInstanceValidatorDstu21); + responseValidator.addValidatorModule(myQuestionnaireResponseValidatorDstu21); + responseValidator.setResponseHeaderValueNoIssues("Validation did not detect any issues"); + responseValidator.setFailOnSeverity(null); + return responseValidator; + } + + @Bean(autowire = Autowire.BY_TYPE) public IServerInterceptor subscriptionSecurityInterceptor() { return new SubscriptionsRequireManualActivationInterceptorDstu21(); } - - + + @Bean() + public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { + JpaTransactionManager retVal = new JpaTransactionManager(); + retVal.setEntityManagerFactory(entityManagerFactory); + return retVal; + } + + /** + * This lets the "@Value" fields reference properties from the properties file + */ + @Bean + public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { + return new PropertySourcesPlaceholderConfigurer(); + } } diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/hapi/validation/FhirQuestionnaireResponseValidator.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/hapi/validation/FhirQuestionnaireResponseValidator.java index 90e8719c96b..505a6225489 100644 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/hapi/validation/FhirQuestionnaireResponseValidator.java +++ b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/hapi/validation/FhirQuestionnaireResponseValidator.java @@ -13,8 +13,9 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.validation.IValidationContext; +import ca.uhn.fhir.validation.IValidatorModule; -public class FhirQuestionnaireResponseValidator extends BaseValidatorBridge { +public class FhirQuestionnaireResponseValidator extends BaseValidatorBridge implements IValidatorModule { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirQuestionnaireResponseValidator.class); private IValidationSupport myValidationSupport; diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/Block.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/Block.java deleted file mode 100644 index 2aed8c85e21..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/Block.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.hl7.fhir.dstu21.model.annotations; - -/* -Copyright (c) 2011+, HL7, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of HL7 nor the names of its contributors may be used to - endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - -*/ - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Class annotation used to indicate a class which is a "block"/"component" type. A block - * is a nested group of fields within a resource definition and can contain other blocks as - * well as data types. - *

- * An example of a block would be Patient.contact - *

- */ -@Retention(RetentionPolicy.RUNTIME) -@Target(value= {ElementType.TYPE}) -public @interface Block { - - /** - * @deprecated Do not use, will be removed - */ - @Deprecated - String name() default ""; - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/Child.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/Child.java deleted file mode 100644 index 6121e42291e..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/Child.java +++ /dev/null @@ -1,165 +0,0 @@ -package org.hl7.fhir.dstu21.model.annotations; - -/* - * #%L - * HAPI FHIR Structures - HL7.org DSTU2 - * %% - * Copyright (C) 2014 - 2015 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% - */ - -/* -Copyright (c) 2011+, HL7, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of HL7 nor the names of its contributors may be used to - endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - -*/ - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.hl7.fhir.dstu21.model.Enumeration; -import org.hl7.fhir.dstu21.model.api.IBase; -import org.hl7.fhir.dstu21.model.api.IBaseEnumFactory; - -/** - * Field annotation for fields within resource and datatype definitions, indicating - * a child of that type. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(value= {ElementType.FIELD}) -public @interface Child { - - /** - * Constant value to supply for {@link #order()} when the order is defined - * elsewhere - */ - int ORDER_UNKNOWN = -1; - - /** - * Constant value to supply for {@link #max()} to indicate '*' (no maximum) - */ - int MAX_UNLIMITED = -1; - - /** - * Constant value to supply for {@link #order()} to indicate that this child should replace the - * entry in the superclass with the same name (and take its {@link Child#order() order} value - * in the process). This is useful if you wish to redefine an existing field in a resource/type - * definition in order to constrain/extend it. - */ - int REPLACE_PARENT = -2; - - /** - * The name of this field, as it will appear in serialized versions of the message - */ - String name(); - - /** - * The order in which this field comes within its parent. The first field should have a - * value of 0, the second a value of 1, etc. - */ - int order() default ORDER_UNKNOWN; - - /** - * The minimum number of repetitions allowed for this child - */ - int min() default 0; - - /** - * The maximum number of repetitions allowed for this child. Should be - * set to {@link #MAX_UNLIMITED} if there is no limit to the number of - * repetitions. - */ - int max() default 1; - - /** - * Lists the allowable types for this field, if the field supports multiple - * types (otherwise does not need to be populated). - *

- * For example, if this field supports either DateTimeDt or BooleanDt types, - * those two classes should be supplied here. - *

- */ - Class[] type() default {}; - - /** - * For children which accept an {@link Enumeration} as the type, this - * field indicates the type to use for the enum factory - */ - Class> enumFactory() default NoEnumFactory.class; - - /** - * Is this element a modifier? - */ - boolean modifier() default false; - - /** - * Should this element be included in the summary view - */ - boolean summary() default false; - - // Not implemented -// /** -// * This value is used when extending a built-in model class and defining a -// * field to replace a field within the built-in class. For example, the {@link Patient} -// * resource has a {@link Patient#getName() name} field, but if you wanted to extend Patient and -// * provide your own implementation of {@link HumanNameDt} (most likely your own subclass of -// * HumanNameDt which adds extensions of your choosing) you could do that using a replacement field. -// */ -// String replaces() default ""; - - public static class NoEnumFactory implements IBaseEnumFactory> { - - private NoEnumFactory() { - // non instantiable - } - - @Override - public Enum fromCode(String theCodeString) throws IllegalArgumentException { - return null; - } - - @Override - public String toCode(Enum theCode) { - return null; - } - - } - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/DatatypeDef.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/DatatypeDef.java deleted file mode 100644 index d9ccc9095fc..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/DatatypeDef.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.hl7.fhir.dstu21.model.annotations; - -/* - * #%L - * HAPI FHIR Structures - HL7.org DSTU2 - * %% - * Copyright (C) 2014 - 2015 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% - */ - -/* -Copyright (c) 2011+, HL7, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of HL7 nor the names of its contributors may be used to - endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - -*/ - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.hl7.fhir.dstu21.model.api.IBaseDatatype; - -/** - * Class annotation to note a class which defines a datatype - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(value= {ElementType.TYPE}) -public @interface DatatypeDef { - - /** - * The defined name of this datatype - */ - String name(); - - /** - * Set this to true (default is false) for any types that are - * really only a specialization of another type. For example, - * {@link BoundCodeDt} is really just a specific type of - * {@link CodeDt} and not a separate datatype, so it should - * have this set to true. - */ - boolean isSpecialization() default false; - - /** - * Indicates that this datatype is a profile of the given datatype, which - * implies certain parsing/encoding rules (e.g. a choice element named - * foo[x] which allows a Markdown value will still be encoded as - * fooString because Markdown is a profile of string. - */ - Class profileOf() default IBaseDatatype.class; - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/Description.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/Description.java deleted file mode 100644 index a4fc828cb63..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/Description.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.hl7.fhir.dstu21.model.annotations; - -/* -Copyright (c) 2011+, HL7, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of HL7 nor the names of its contributors may be used to - endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - -*/ - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation which may be placed on a resource/datatype definition, or a field, or - * a search parameter definition in order to provide documentation for that item. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(value= {ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER, ElementType.METHOD}) -public @interface Description { - - /** - * Optional short name for this child - */ - String shortDefinition() default ""; - - /** - * Optional formal definition for this child - */ - String formalDefinition() default ""; - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/Extension.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/Extension.java deleted file mode 100644 index b9ace078853..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/Extension.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.hl7.fhir.dstu21.model.annotations; - -/* -Copyright (c) 2011+, HL7, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of HL7 nor the names of its contributors may be used to - endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - -*/ - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Field modifier to be placed on a child field (a field also annotated with the {@link Child} annotation) which - * indicates that this field is an extension. - */ -@Target(value = { ElementType.FIELD }) -@Retention(RetentionPolicy.RUNTIME) -public @interface Extension { - - /** - * This parameter affects how the extension is treated when the element definition containing this resource is - * exported to a profile. - * - *

- * If set to true, the resource is taken to be a local resource and its definition is exported - * along with the reference. Use this option for extension defintions that you have added locally (i.e. within your - * own organization) - *

- * - *

- * If set to false, the resource is taken to be a remote resource and its definition is - * not exported to the profile. Use this option for extensions that are defined by other organizations (i.e. - * by regional authorities or jurisdictional governments) - *

- */ - boolean definedLocally(); - - /** - * Returns true if this extension is a modifier extension - */ - boolean isModifier(); - - /** - * The URL associated with this extension - */ - String url(); - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/ResourceDef.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/ResourceDef.java deleted file mode 100644 index d70bf9c25e8..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/ResourceDef.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.hl7.fhir.dstu21.model.annotations; - -/* -Copyright (c) 2011+, HL7, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of HL7 nor the names of its contributors may be used to - endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - -*/ - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Class annotation which indicates a resource definition class - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(value= {ElementType.TYPE}) -public @interface ResourceDef { - - /** - * The name of the resource (e.g. "Patient" or "DiagnosticReport") - */ - String name(); - - /** - * Not currently used - */ - String id() default ""; - - /** - * The URL indicating the profile for this resource definition, if known - */ - String profile() default ""; - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/SearchParamDefinition.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/SearchParamDefinition.java deleted file mode 100644 index 34c8cb6331d..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/annotations/SearchParamDefinition.java +++ /dev/null @@ -1,79 +0,0 @@ -package org.hl7.fhir.dstu21.model.annotations; - -/* -Copyright (c) 2011+, HL7, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of HL7 nor the names of its contributors may be used to - endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - -*/ - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.hl7.fhir.dstu21.model.Resource; - -@Target(value=ElementType.FIELD) -@Retention(RetentionPolicy.RUNTIME) -public @interface SearchParamDefinition { - - /** - * The name for this parameter - */ - String name(); - - /** - * The path for this parameter - */ - String path(); - - /** - * A description of this parameter - */ - String description() default ""; - - /** - * The type for this parameter, e.g. "string", or "token" - */ - String type() default "string"; - - /** - * If the parameter is of type "composite", this parameter lists the names of the parameters - * which this parameter is a composite of. E.g. "name-value-token" is a composite of "name" and "value-token". - *

- * If the parameter is not a composite, this parameter must be empty - *

- */ - String[] compositeOf() default {}; - - /** - * For search params of type "reference", this can optionally be used to - * specify the resource type(s) that this parameter applies to. - */ - Class[] target() default {}; - - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IAnyResource.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IAnyResource.java deleted file mode 100644 index 2e353ed9f36..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IAnyResource.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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 interface IAnyResource extends IBaseResource { - - String getId(); - - IAnyResource setId(String theId); - - IIdType getIdElement(); - - IBaseMetaType getMeta(); - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBackboneElement.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBackboneElement.java deleted file mode 100644 index 657eabe9e03..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBackboneElement.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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 interface IBackboneElement extends IBase { - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBase.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBase.java deleted file mode 100644 index dc6ff680398..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBase.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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% - */ - -/** - * This interface is a simple marker for anything which is an HL7 - * structure of some kind. It is provided mostly to simplify convergence - * between the HL7.org structures and the HAPI ones. - */ -public interface IBase { - - boolean isEmpty(); - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseBackboneElement.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseBackboneElement.java deleted file mode 100644 index b1831997211..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseBackboneElement.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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 interface IBaseBackboneElement extends IBase, IBaseHasExtensions, IBaseHasModifierExtensions { - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseBinary.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseBinary.java deleted file mode 100644 index ac337746cd2..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseBinary.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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 interface IBaseBinary extends IBaseResource { - - byte[] getContent(); - - String getContentAsBase64(); - - String getContentType(); - - IBaseBinary setContent(byte[] theContent); - - IBaseBinary setContentAsBase64(String theContent); - - IBaseBinary setContentType(String theContentType); -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseBooleanDatatype.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseBooleanDatatype.java deleted file mode 100644 index 5e50708e185..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseBooleanDatatype.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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 interface IBaseBooleanDatatype extends IPrimitiveType { - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseBundle.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseBundle.java deleted file mode 100644 index 2649a0cc2e9..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseBundle.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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 interface IBaseBundle extends IBaseResource { - - /** - * Constant for links provided in the bundle. This constant is used in the - * link.type field to indicate that the given link is for - * the next page of results. - */ - public static final String LINK_NEXT = "next"; - - /** - * Constant for links provided in the bundle. This constant is used in the - * link.type field to indicate that the given link is for - * the previous page of results. - */ - public static final String LINK_PREV = "prev"; - - /** - * Constant for links provided in the bundle. This constant is used in the - * link.type field to indicate that the given link is for - * this bundle. - */ - public static final String LINK_SELF = "self"; - - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseCoding.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseCoding.java deleted file mode 100644 index 91fb967fdd6..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseCoding.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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 interface IBaseCoding { - - IBaseCoding setSystem(String theScheme); - - IBaseCoding setCode(String theTerm); - - IBaseCoding setDisplay(String theLabel); - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseConformance.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseConformance.java deleted file mode 100644 index c5cd34342ae..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseConformance.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - - -public interface IBaseConformance extends IBaseResource { - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseDatatype.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseDatatype.java deleted file mode 100644 index 7c39b772425..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseDatatype.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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 interface IBaseDatatype extends IBase { - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseDatatypeElement.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseDatatypeElement.java deleted file mode 100644 index 35d1ca5e2dd..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseDatatypeElement.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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 interface IBaseDatatypeElement extends IBase { - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseDecimalDatatype.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseDecimalDatatype.java deleted file mode 100644 index d09f7d27295..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseDecimalDatatype.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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% - */ - -import java.math.BigDecimal; - -public interface IBaseDecimalDatatype extends IPrimitiveType { - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseElement.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseElement.java deleted file mode 100644 index f97ff7295ed..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseElement.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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 interface IBaseElement { - - IBaseElement setId(String theValue); - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseEnumFactory.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseEnumFactory.java deleted file mode 100644 index a605e73c5e5..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseEnumFactory.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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 interface IBaseEnumFactory> { - - /** - * Read an enumeration value from the string that represents it on the XML or JSON - * - * @param codeString the value found in the XML or JSON - * @return the enumeration value - * @throws IllegalArgumentException is the value is not known - */ - public T fromCode(String codeString) throws IllegalArgumentException; - - /** - * Get the XML/JSON representation for an enumerated value - * - * @param code - the enumeration value - * @return the XML/JSON representation - */ - public String toCode(T code); - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseEnumeration.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseEnumeration.java deleted file mode 100644 index 3e39e1d041d..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseEnumeration.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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 interface IBaseEnumeration> extends IPrimitiveType { - - // Marker interface - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseExtension.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseExtension.java deleted file mode 100644 index 78620bf4725..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseExtension.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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% - */ - -import java.util.List; - -public interface IBaseExtension extends ICompositeType { - - List getExtension(); - - String getUrl(); - - IBaseDatatype getValue(); - - T setUrl(String theUrl); - - T setValue(IBaseDatatype theValue); - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseFhirEnum.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseFhirEnum.java deleted file mode 100644 index c6ed0122fa4..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseFhirEnum.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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% - */ - - - -/* -Copyright (c) 2011+, HL7, Inc -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of HL7 nor the names of its contributors may be used to - endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - -*/ - -/** - * Interface to be implemented by all built-in FHIR enumerations (i.e. the - * actual FHIR-defined Java Enum will implement this interface) - */ -public interface IBaseFhirEnum { - - /** - * Get the XML/JSON representation for an enumerated value - * @return the XML/JSON representation - */ - public String toCode(); - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseHasExtensions.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseHasExtensions.java deleted file mode 100644 index f438f30be9f..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseHasExtensions.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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% - */ - -import java.util.List; - -public interface IBaseHasExtensions { - - public List> getExtension(); - - public IBaseExtension addExtension(); - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseHasModifierExtensions.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseHasModifierExtensions.java deleted file mode 100644 index 0d3e2e83163..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseHasModifierExtensions.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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% - */ - -import java.util.List; - -public interface IBaseHasModifierExtensions { - - public List> getModifierExtension(); - - public IBaseExtension addModifierExtension(); - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseIntegerDatatype.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseIntegerDatatype.java deleted file mode 100644 index f8e0359c315..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseIntegerDatatype.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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 interface IBaseIntegerDatatype extends IPrimitiveType { - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseMetaType.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseMetaType.java deleted file mode 100644 index ecfa69de6be..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseMetaType.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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% - */ - -import java.util.Date; - -public interface IBaseMetaType extends ICompositeType { - - IBaseCoding addTag(); - - IBaseMetaType setLastUpdated(Date theHeaderDateValue); - - Date getLastUpdated(); - - String getVersionId(); - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseOperationOutcome.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseOperationOutcome.java deleted file mode 100644 index bdb89b2c28b..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseOperationOutcome.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -public interface IBaseOperationOutcome extends IBaseResource { - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseParameters.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseParameters.java deleted file mode 100644 index 29052292c99..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseParameters.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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 interface IBaseParameters extends IBaseResource { - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseReference.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseReference.java deleted file mode 100644 index 2ebe99d9503..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseReference.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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 interface IBaseReference extends ICompositeType { - - IBaseResource getResource(); - - void setResource(IBaseResource theResource); - - IIdType getReferenceElement(); - - IBaseReference setReference(String theReference); - - IBase setDisplay(String theValue); - - IPrimitiveType getDisplayElement(); -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseResource.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseResource.java deleted file mode 100644 index 93af9f5a0a2..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseResource.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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% - */ - -/** - * For now, this is a simple marker interface indicating that a class is a resource type. - * There are two concrete types of implementations of this interrface. The first are - * HL7.org's Resource structures (e.g. - * org.hl7.fhir.instance.model.Patient) and - * the second are HAPI's Resource structures, e.g. - * ca.uhn.fhir.model.dstu.resource.Patient) - */ -public interface IBaseResource extends IBase { - - IIdType getIdElement(); - - IBaseResource setId(String theId); - - IBaseResource setId(IIdType theId); - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseXhtml.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseXhtml.java deleted file mode 100644 index cbdfee1c81a..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IBaseXhtml.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - - -public interface IBaseXhtml extends IPrimitiveType { - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/ICompositeType.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/ICompositeType.java deleted file mode 100644 index 44252c7dde1..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/ICompositeType.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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 interface ICompositeType extends IBaseDatatype { - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IDomainResource.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IDomainResource.java deleted file mode 100644 index 2f4912c0f81..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IDomainResource.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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% - */ - -import java.util.List; - -public interface IDomainResource extends IAnyResource { - - List getContained(); - - INarrative getText(); - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IIdType.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IIdType.java deleted file mode 100644 index ef591c3aec5..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IIdType.java +++ /dev/null @@ -1,138 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - - - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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% - */ - -/** - * Base interface for ID datatype. - * - *

- * Concrete Implementations: This interface is often returned and/or accepted by methods in HAPI's API - * where either {@link ca.uhn.fhir.model.primitive.IdDt} (the HAPI structure ID type) or - * org.hl7.fhir.instance.model.IdType (the RI structure ID type) will be used, depending on - * which version of the strctures your application is using. - *

- */ -public interface IIdType { - - void applyTo(IBaseResource theResource); - - /** - * Returns the server base URL if this ID contains one. For example, the base URL is - * the 'http://example.com/fhir' in the following ID: http://example.com/fhir/Patient/123/_history/55 - */ - String getBaseUrl(); - - /** - * Returns only the logical ID part of this ID. For example, given the ID - * "http://example,.com/fhir/Patient/123/_history/456", this method would - * return "123". - */ - String getIdPart(); - - /** - * Returns the ID part of this ID (e.g. in the ID http://example.com/Patient/123/_history/456 this would be the - * part "123") parsed as a {@link Long}. - * - * @throws NumberFormatException If the value can't be parsed as a long - */ - Long getIdPartAsLong(); - - String getResourceType(); - - /** - * Returns the value of this ID. Note that this value may be a fully qualified URL, a relative/partial URL, or a simple ID. Use {@link #getIdPart()} to get just the ID portion. - * - * @see #getIdPart() - */ - String getValue(); - - String getVersionIdPart(); - - /** - * Returns the version ID part of this ID (e.g. in the ID http://example.com/Patient/123/_history/456 this would be the - * part "456") parsed as a {@link Long}. - * - * @throws NumberFormatException If the value can't be parsed as a long - */ - Long getVersionIdPartAsLong(); - - boolean hasBaseUrl(); - - /** - * Returns true if this ID contains an actual ID part. For example, the ID part is - * the '123' in the following ID: http://example.com/fhir/Patient/123/_history/55 - */ - boolean hasIdPart(); - - boolean hasResourceType(); - - boolean hasVersionIdPart(); - - /** - * Returns true if this ID contains an absolute URL (in other words, a URL starting with "http://" or "https://" - */ - boolean isAbsolute(); - - boolean isEmpty(); - - /** - * Returns true if the {@link #getIdPart() ID part of this object} is valid according to the FHIR rules for valid IDs. - *

- * The FHIR specification states: - * Any combination of upper or lower case ASCII letters ('A'..'Z', and 'a'..'z', numerals ('0'..'9'), '-' and '.', with a length limit of 64 characters. (This might be an integer, an un-prefixed OID, UUID or any other identifier pattern that meets these constraints.) regex: [A-Za-z0-9\-\.]{1,64} - *

- */ - boolean isIdPartValid(); - - /** - * Returns true if the {@link #getIdPart() ID part of this object} contains - * only numbers - */ - boolean isIdPartValidLong(); - - /** - * Returns true if the ID is a local reference (in other words, it begins with the '#' character) - */ - boolean isLocal(); - - /** - * Returns true if the {@link #getVersionIdPart() version ID part of this object} contains - * only numbers - */ - boolean isVersionIdPartValidLong(); - - IIdType setValue(String theString); - - IIdType toUnqualified(); - - IIdType toUnqualifiedVersionless(); - - IIdType toVersionless(); - - IIdType withResourceType(String theResName); - - IIdType withServerBase(String theServerBase, String theResourceName); - - IIdType withVersion(String theVersion); - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/INarrative.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/INarrative.java deleted file mode 100644 index 7f05ad3b645..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/INarrative.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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 interface INarrative extends ICompositeType { - - boolean isEmpty(); - - // TODO: use less broad exception type here - public void setDivAsString(String theString) throws Exception; - - // TODO: use less broad exception type here - public String getDivAsString() throws Exception; - -} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IPrimitiveType.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IPrimitiveType.java deleted file mode 100644 index ac3a5acfacd..00000000000 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu21/model/api/IPrimitiveType.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.hl7.fhir.dstu21.model.api; - - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * Copyright (C) 2014 - 2015 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 interface IPrimitiveType extends IBaseDatatype { - - void setValueAsString(String theValue) throws IllegalArgumentException; - - String getValueAsString(); - - T getValue(); - - IPrimitiveType setValue(T theValue) throws IllegalArgumentException; - -} diff --git a/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/rest/server/RequestValidatingInterceptorTest.java b/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/rest/server/RequestValidatingInterceptorTest.java new file mode 100644 index 00000000000..8fa0eb05112 --- /dev/null +++ b/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/rest/server/RequestValidatingInterceptorTest.java @@ -0,0 +1,311 @@ +package ca.uhn.fhir.rest.server; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +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.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.hl7.fhir.dstu21.hapi.validation.FhirInstanceValidator; +import org.hl7.fhir.dstu21.model.Enumerations.AdministrativeGender; +import org.hl7.fhir.dstu21.model.IdType; +import org.hl7.fhir.dstu21.model.Patient; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.annotation.Create; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.OptionalParam; +import ca.uhn.fhir.rest.annotation.ResourceParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor; +import ca.uhn.fhir.util.PortUtil; +import ca.uhn.fhir.validation.IValidatorModule; + +public class RequestValidatingInterceptorTest { + private static CloseableHttpClient ourClient; + + private static FhirContext ourCtx = FhirContext.forDstu2_1(); + private static boolean ourLastRequestWasSearch; + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RequestValidatingInterceptorTest.class); + private static int ourPort; + + private static Server ourServer; + + private static RestfulServer ourServlet; + + + + private RequestValidatingInterceptor myInterceptor; + + @Before + public void before() { + ourLastRequestWasSearch = false; + while (ourServlet.getInterceptors().size() > 0) { + ourServlet.unregisterInterceptor(ourServlet.getInterceptors().get(0)); + } + + myInterceptor = new RequestValidatingInterceptor(); +// myInterceptor.setFailOnSeverity(ResultSeverityEnum.ERROR); +// myInterceptor.setAddResponseHeaderOnSeverity(ResultSeverityEnum.INFORMATION); +// myInterceptor.setResponseHeaderName("X-RESP"); +// myInterceptor.setResponseHeaderValue(RequestValidatingInterceptor.DEFAULT_RESPONSE_HEADER_VALUE); + + ourServlet.registerInterceptor(myInterceptor); + } + + @Test + public void testCreateJsonInvalidNoValidatorsSpecified() throws Exception { + Patient patient = new Patient(); + patient.addIdentifier().setValue("002"); + patient.setGender(AdministrativeGender.MALE); + patient.addContact().addRelationship().setText("FOO"); + String encoded = ourCtx.newJsonParser().encodeResourceToString(patient); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); + httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_JSON, "UTF-8"))); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", status); + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(422, status.getStatusLine().getStatusCode()); + assertThat(status.toString(), containsString("X-HAPI-Request-Validation")); + assertThat(responseContent, containsString("")); + } + + @Test + public void testCreateJsonInvalidNoFailure() throws Exception { + myInterceptor.setFailOnSeverity(null); + + Patient patient = new Patient(); + patient.addIdentifier().setValue("002"); + patient.setGender(AdministrativeGender.MALE); + patient.addContact().addRelationship().setText("FOO"); + String encoded = ourCtx.newJsonParser().encodeResourceToString(patient); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); + httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_JSON, "UTF-8"))); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", status); + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(201, status.getStatusLine().getStatusCode()); + assertThat(status.toString(), containsString("X-HAPI-Request-Validation")); + assertThat(responseContent, not(containsString(""))); + } + + @Test + public void testCreateJsonValidNoValidatorsSpecified() throws Exception { + Patient patient = new Patient(); + patient.addIdentifier().setValue("002"); + patient.setGender(AdministrativeGender.MALE); + String encoded = ourCtx.newJsonParser().encodeResourceToString(patient); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); + httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_JSON, "UTF-8"))); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", status); + ourLog.trace("Response was:\n{}", responseContent); + + assertEquals(201, status.getStatusLine().getStatusCode()); + assertThat(status.toString(), not(containsString("X-HAPI-Request-Validation"))); + } + + @Test + public void testCreateJsonValidNoValidatorsSpecifiedDefaultMessage() throws Exception { + myInterceptor.setResponseHeaderValueNoIssues("NO ISSUES"); + + Patient patient = new Patient(); + patient.addIdentifier().setValue("002"); + patient.setGender(AdministrativeGender.MALE); + String encoded = ourCtx.newJsonParser().encodeResourceToString(patient); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); + httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_JSON, "UTF-8"))); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", status); + ourLog.trace("Response was:\n{}", responseContent); + + assertEquals(201, status.getStatusLine().getStatusCode()); + assertThat(status.toString(), (containsString("X-HAPI-Request-Validation: NO ISSUES"))); + } + + @Test + public void testCreateXmlInvalidNoValidatorsSpecified() throws Exception { + Patient patient = new Patient(); + patient.addIdentifier().setValue("002"); + patient.setGender(AdministrativeGender.MALE); + patient.addContact().addRelationship().setText("FOO"); + String encoded = ourCtx.newXmlParser().encodeResourceToString(patient); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); + httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", status); + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(422, status.getStatusLine().getStatusCode()); + assertThat(status.toString(), containsString("X-HAPI-Request-Validation")); + } + + @Test + public void testCreateXmlInvalidInstanceValidator() throws Exception { + IValidatorModule module = new FhirInstanceValidator(); + myInterceptor.addValidatorModule(module); + + Patient patient = new Patient(); + patient.addIdentifier().setValue("002"); + patient.setGender(AdministrativeGender.MALE); + patient.addContact().addRelationship().setText("FOO"); + String encoded = ourCtx.newXmlParser().encodeResourceToString(patient); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); + httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", status); + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(422, status.getStatusLine().getStatusCode()); + assertThat(status.toString(), containsString("X-HAPI-Request-Validation")); + } + + @Test + public void testSearch() throws Exception { + HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient?foo=bar"); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", status); + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertThat(status.toString(), not(containsString("X-HAPI-Request-Validation"))); + assertEquals(true, ourLastRequestWasSearch); + } + + @Test + public void testCreateXmlValidNoValidatorsSpecified() throws Exception { + Patient patient = new Patient(); + patient.addIdentifier().setValue("002"); + patient.setGender(AdministrativeGender.MALE); + String encoded = ourCtx.newXmlParser().encodeResourceToString(patient); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); + httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", status); + ourLog.trace("Response was:\n{}", responseContent); + + assertEquals(201, status.getStatusLine().getStatusCode()); + assertThat(status.toString(), not(containsString("X-HAPI-Request-Validation"))); + } + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + PatientProvider patientProvider = new PatientProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + ourServlet = new RestfulServer(ourCtx); + ourServlet.setResourceProviders(patientProvider); + ServletHolder servletHolder = new ServletHolder(ourServlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + public static class PatientProvider implements IResourceProvider { + + + @Create() + public MethodOutcome createPatient(@ResourceParam Patient thePatient, @IdParam IdType theIdParam) { + return new MethodOutcome(new IdDt("Patient/001/_history/002")); + } + + @Override + public Class getResourceType() { + return Patient.class; + } + + @Search + public List search(@OptionalParam(name="foo") StringParam theString) { + ourLastRequestWasSearch = true; + return new ArrayList(); + } + + } + +} diff --git a/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/rest/server/ResponseValidatingInterceptorTest.java b/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/rest/server/ResponseValidatingInterceptorTest.java new file mode 100644 index 00000000000..8025d33a3a1 --- /dev/null +++ b/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/rest/server/ResponseValidatingInterceptorTest.java @@ -0,0 +1,253 @@ +package ca.uhn.fhir.rest.server; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.hl7.fhir.dstu21.hapi.validation.FhirInstanceValidator; +import org.hl7.fhir.dstu21.model.Enumerations.AdministrativeGender; +import org.hl7.fhir.dstu21.model.Patient; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.rest.annotation.OptionalParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.server.interceptor.ResponseValidatingInterceptor; +import ca.uhn.fhir.util.PortUtil; +import ca.uhn.fhir.validation.IValidatorModule; + +public class ResponseValidatingInterceptorTest { + private static CloseableHttpClient ourClient; + + private static FhirContext ourCtx = FhirContext.forDstu2_1(); + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResponseValidatingInterceptorTest.class); + private static int ourPort; + private static Server ourServer; + private static RestfulServer ourServlet; + private ResponseValidatingInterceptor myInterceptor; + public static IBaseResource myReturnResource; + + @Before + public void before() { + myReturnResource = null; + while (ourServlet.getInterceptors().size() > 0) { + ourServlet.unregisterInterceptor(ourServlet.getInterceptors().get(0)); + } + + myInterceptor = new ResponseValidatingInterceptor(); +// myInterceptor.setFailOnSeverity(ResultSeverityEnum.ERROR); +// myInterceptor.setAddResponseHeaderOnSeverity(ResultSeverityEnum.INFORMATION); +// myInterceptor.setResponseHeaderName("X-RESP"); +// myInterceptor.setResponseHeaderValue(RequestValidatingInterceptor.DEFAULT_RESPONSE_HEADER_VALUE); + + ourServlet.registerInterceptor(myInterceptor); + } + + /** + * Ignored until #264 is fixed + */ + @Test + @Ignore + public void testSearchJsonInvalidNoValidatorsSpecified() throws Exception { + Patient patient = new Patient(); + patient.addIdentifier().setValue("002"); + patient.setGender(AdministrativeGender.MALE); + patient.addContact().addRelationship().setText("FOO"); + myReturnResource = patient; + + HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient?foo=bar"); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", status); + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(422, status.getStatusLine().getStatusCode()); + assertThat(status.toString(), containsString("X-HAPI-Response-Validation")); + assertThat(responseContent, containsString("")); + } + + + @Test + public void testSearchJsonValidNoValidatorsSpecified() throws Exception { + Patient patient = new Patient(); + patient.addIdentifier().setValue("002"); + patient.setGender(AdministrativeGender.MALE); + myReturnResource = patient; + + HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient?foo=bar"); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", status); + ourLog.trace("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertThat(status.toString(), not(containsString("X-HAPI-Response-Validation"))); + } + + @Test + public void testSearchJsonValidNoValidatorsSpecifiedDefaultMessage() throws Exception { + myInterceptor.setResponseHeaderValueNoIssues("NO ISSUES"); + + Patient patient = new Patient(); + patient.addIdentifier().setValue("002"); + patient.setGender(AdministrativeGender.MALE); + myReturnResource = patient; + + HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient?foo=bar"); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", status); + ourLog.trace("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertThat(status.toString(), (containsString("X-HAPI-Response-Validation: NO ISSUES"))); + } + + /** + * Ignored until #264 is fixed + */ + @Test + @Ignore + public void testSearchXmlInvalidNoValidatorsSpecified() throws Exception { + Patient patient = new Patient(); + patient.addIdentifier().setValue("002"); + patient.setGender(AdministrativeGender.MALE); + patient.addContact().addRelationship().setText("FOO"); + myReturnResource = patient; + + HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient?foo=bar"); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", status); + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(422, status.getStatusLine().getStatusCode()); + assertThat(status.toString(), containsString("X-HAPI-Response-Validation")); + } + + @Test + public void testSearchXmlInvalidInstanceValidator() throws Exception { + IValidatorModule module = new FhirInstanceValidator(); + myInterceptor.addValidatorModule(module); + + Patient patient = new Patient(); + patient.addIdentifier().setValue("002"); + patient.setGender(AdministrativeGender.MALE); + patient.addContact().addRelationship().setText("FOO"); + myReturnResource = patient; + + HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient?foo=bar"); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", status); + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(422, status.getStatusLine().getStatusCode()); + assertThat(status.toString(), containsString("X-HAPI-Response-Validation")); + } + + @Test + public void testSearchXmlValidNoValidatorsSpecified() throws Exception { + Patient patient = new Patient(); + patient.addIdentifier().setValue("002"); + patient.setGender(AdministrativeGender.MALE); + myReturnResource = patient; + + HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient?foo=bar"); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", status); + ourLog.trace("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertThat(status.toString(), not(containsString("X-HAPI-Response-Validation"))); + } + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + PatientProvider patientProvider = new PatientProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + ourServlet = new RestfulServer(ourCtx); + ourServlet.setResourceProviders(patientProvider); + ServletHolder servletHolder = new ServletHolder(ourServlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + public static class PatientProvider implements IResourceProvider { + + @Override + public Class getResourceType() { + return Patient.class; + } + + @Search + public ArrayList search(@OptionalParam(name="foo") StringParam theString) { + ArrayList retVal = new ArrayList(); + myReturnResource.setId("1"); + retVal.add(myReturnResource); + return retVal; + } + + } + +} diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/hapi/validation/FhirQuestionnaireResponseValidator.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/hapi/validation/FhirQuestionnaireResponseValidator.java index 14dc49bdeae..adc9117edd4 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/hapi/validation/FhirQuestionnaireResponseValidator.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/hapi/validation/FhirQuestionnaireResponseValidator.java @@ -23,8 +23,9 @@ import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.util.ResourceReferenceInfo; import ca.uhn.fhir.validation.IResourceLoader; import ca.uhn.fhir.validation.IValidationContext; +import ca.uhn.fhir.validation.IValidatorModule; -public class FhirQuestionnaireResponseValidator extends BaseValidatorBridge { +public class FhirQuestionnaireResponseValidator extends BaseValidatorBridge implements IValidatorModule { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory .getLogger(FhirQuestionnaireResponseValidator.class); diff --git a/pom.xml b/pom.xml index 1648afd80df..665c901a6c7 100644 --- a/pom.xml +++ b/pom.xml @@ -597,7 +597,7 @@ org.springframework.data spring-data-jpa - 1.9.0.RELEASE + 1.9.2.RELEASE org.springframework diff --git a/src/changes/changes.xml b/src/changes/changes.xml index b03d4491a55..c421b917e9c 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -26,6 +26,24 @@ codebase. This dependency was accidentally introduced in 1.3, and animal-sniffer-plugin failed to detect it (sigh). + + Add two new server interceptors: + RequestValidatingInterceptor + and + ResponseValidatingInterceptor + ]]> + which can be used to validate incoming requests or outgoing responses using the standard FHIR validation + tools. See the + Server Validation Page + ]]> + for examples of how to use these interceptors. These intereptors have both + been enabled on the + public test page. + ]]> + Make IBoundCodeableConcept and IValueSetEnumBinder serializable, fixing an issue when trying to serialize model classes containing @@ -78,7 +96,7 @@ Support target parameter type in _include / _revinclude values, e.g. _include=Patient:careProvider:Organization. Thanks to Joe Portner for reporting! - + Use ResponseHighlighterInterceptor in the hapi-fhir-jpaserver-example project to provide nice syntax highlighting. Thanks to Rob Hausam for diff --git a/src/site/xdoc/doc_rest_server_interceptor.xml b/src/site/xdoc/doc_rest_server_interceptor.xml index f055d653ad5..37d0bf15aa3 100644 --- a/src/site/xdoc/doc_rest_server_interceptor.xml +++ b/src/site/xdoc/doc_rest_server_interceptor.xml @@ -251,6 +251,43 @@ + + +

+ The + RequestValidatingInterceptor + and + ResponseValidatingInterceptor + can be used to perform validation of resources on their way into and out of the server respectively. +

+

+ The RequestValidatingInterceptor looks at resources coming into the server (e.g. for create, + update, $operations, transactions, etc.) and validates them. The ResponseValidatingInterceptor + looks at resources being returned by the server (e.g. for read, search, $operations, etc.) and + validates them. +

+

+ These interceptors can be configured to add headers to the response, fail the response + (returning an HTTP 422 and throwing an exception in the process), or to add to the + OperationOutcome returned by the server. +

+

+ See the Validation Page for information on + available IValidationModule validation modules. Any of the Resource Validators + listed on that page can be enabled in these interceptors (note that the Parser Validators + can not). +

+

+ The following example shows how to register this interceptor within + a FHIR RESTful server. +

+ + + + + +
+
diff --git a/src/site/xdoc/doc_validation.xml b/src/site/xdoc/doc_validation.xml index 0a1abfe4c97..7de39533ba3 100644 --- a/src/site/xdoc/doc_validation.xml +++ b/src/site/xdoc/doc_validation.xml @@ -20,12 +20,14 @@ of a resource. It can be used to catch input data that is impossible to fit into the HAPI data model. For example, it can be used to throw exceptions - or display error messages if a resource being parsed contains tags for which - there are no appropriate fields in a HAPI data structure. + or display error messages if a resource being parsed contains elements for which + there are no appropriate fields in a HAPI data structure. This is useful in order to ensure + that no data is being lost during parsing, but is less comprehensive than resource validation + against raw text data.
  • Resource Validation - is validation of the parsed (or constructed) resource against + is validation of the raw or parsed resource against the official FHIR validation rules (e.g. Schema/Schematron/Profile/StructureDefinition/ValueSet).