From 31d16fca0325075f359729b71fd5b8b35c1c7676 Mon Sep 17 00:00:00 2001 From: Phillip Warner Date: Fri, 29 Apr 2016 12:50:15 -0600 Subject: [PATCH] Updated jaxrsserver base and example for DSTU3 Added support for specifying DSTU3 in the constructors, where the default is DSTU2, to maintain backwards compatibility. Updated interface usage to IBase... (e.g., IResource -> IBaseResource), which is compatible with DSTU3. Added tests specifically for DSTU3; kept the existing tests as DSTU2. Provided examples for DSTU3. --- .../uhn/fhir/rest/client/GenericClient.java | 7 +- .../uhn/fhir/rest/client/IGenericClient.java | 3 +- .../method/ValidateMethodBindingDstu3.java | 84 + hapi-fhir-jaxrsserver-base/pom.xml | 5 + .../AbstractJaxRsConformanceProvider.java | 54 +- .../server/AbstractJaxRsPageProvider.java | 14 + .../jaxrs/server/AbstractJaxRsProvider.java | 18 +- .../server/AbstractJaxRsResourceProvider.java | 34 +- .../fhir/jaxrs/server/util/JaxRsRequest.java | 25 +- .../client/GenericJaxRsClientDstu3Test.java | 2207 +++++++++++++++++ ...ractJaxRsConformanceProviderDstu3Test.java | 110 + ...bstractJaxRsResourceProviderDstu3Test.java | 443 ++++ ...TestJaxRsConformanceRestProviderDstu3.java | 34 + .../TestJaxRsDummyPatientProviderDstu3.java | 21 + .../test/TestJaxRsMockPageProviderDstu3.java | 26 + ...TestJaxRsMockPatientRestProviderDstu3.java | 141 ++ .../util/JaxRsMethodBindingsDstu3Test.java | 129 + .../server/util/JaxRsRequestDstu3Test.java | 119 + .../server/util/JaxRsResponseDstu3Test.java | 159 ++ .../JaxRsConformanceProviderDstu3.java | 46 + .../example/JaxRsPageProviderDstu3.java | 27 + .../JaxRsPatientRestProviderDstu3.java | 258 ++ .../JaxRsPatientProviderDstu3Test.java | 315 +++ 23 files changed, 4255 insertions(+), 24 deletions(-) create mode 100644 hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ValidateMethodBindingDstu3.java create mode 100644 hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/client/GenericJaxRsClientDstu3Test.java create mode 100644 hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderDstu3Test.java create mode 100644 hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProviderDstu3Test.java create mode 100644 hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsConformanceRestProviderDstu3.java create mode 100644 hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsDummyPatientProviderDstu3.java create mode 100644 hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPageProviderDstu3.java create mode 100644 hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProviderDstu3.java create mode 100644 hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/util/JaxRsMethodBindingsDstu3Test.java create mode 100644 hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/util/JaxRsRequestDstu3Test.java create mode 100644 hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/util/JaxRsResponseDstu3Test.java create mode 100644 hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsConformanceProviderDstu3.java create mode 100644 hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPageProviderDstu3.java create mode 100644 hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientRestProviderDstu3.java create mode 100644 hapi-fhir-jaxrsserver-example/src/test/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientProviderDstu3Test.java diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java index 7aa3bda5ab6..042333a6197 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java @@ -43,6 +43,7 @@ import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseConformance; import org.hl7.fhir.instance.model.api.IBaseDatatype; import org.hl7.fhir.instance.model.api.IBaseMetaType; +import org.hl7.fhir.instance.model.api.IBaseOperationOutcome; import org.hl7.fhir.instance.model.api.IBaseParameters; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; @@ -169,7 +170,7 @@ public class GenericClient extends BaseClient implements IGenericClient { } @Override - public BaseConformance conformance() { + public IBaseConformance conformance() { if (myContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU2_HL7ORG)) { throw new IllegalArgumentException("Must call fetchConformance() instead of conformance() for RI/DSTU3+ structures"); } @@ -183,7 +184,7 @@ public class GenericClient extends BaseClient implements IGenericClient { Class conformance = (Class) myContext.getResourceDefinition("Conformance").getImplementingClass(); ResourceResponseHandler binding = new ResourceResponseHandler(conformance); - BaseConformance resp = invokeClient(myContext, binding, invocation, myLogRequestAndResponse); + IBaseConformance resp = invokeClient(myContext, binding, invocation, myLogRequestAndResponse); return resp; } @@ -2308,7 +2309,7 @@ public class GenericClient extends BaseClient implements IGenericClient { public MethodOutcome execute() { BaseHttpClientInvocation invocation = ValidateMethodBindingDstu2.createValidateInvocation(myContext, myResource); ResourceResponseHandler handler = new ResourceResponseHandler(null, null); - BaseOperationOutcome outcome = invoke(null, handler, invocation); + IBaseOperationOutcome outcome = invoke(null, handler, invocation); MethodOutcome retVal = new MethodOutcome(); retVal.setOperationOutcome(outcome); return retVal; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IGenericClient.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IGenericClient.java index 4c27657931e..4bd785e753b 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IGenericClient.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IGenericClient.java @@ -23,6 +23,7 @@ package ca.uhn.fhir.rest.client; import java.util.List; import java.util.Map; +import org.hl7.fhir.instance.model.api.IBaseConformance; import org.hl7.fhir.instance.model.api.IBaseResource; import ca.uhn.fhir.model.api.Bundle; @@ -58,7 +59,7 @@ public interface IGenericClient extends IRestfulClient { * @deprecated Use {@link #fetchConformance()} instead */ @Deprecated - BaseConformance conformance(); + IBaseConformance conformance(); /** * Fluent method for the "create" operation, which creates a new resource instance on the server diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ValidateMethodBindingDstu3.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ValidateMethodBindingDstu3.java new file mode 100644 index 00000000000..fc76589cacb --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ValidateMethodBindingDstu3.java @@ -0,0 +1,84 @@ +package ca.uhn.fhir.rest.method; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 - 2016 University Health Network + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import org.hl7.fhir.instance.model.api.IBaseParameters; +import org.hl7.fhir.instance.model.api.IBaseResource; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.valueset.BundleTypeEnum; +import ca.uhn.fhir.rest.annotation.OperationParam; +import ca.uhn.fhir.rest.annotation.Validate; +import ca.uhn.fhir.rest.client.BaseHttpClientInvocation; +import ca.uhn.fhir.rest.param.ResourceParameter; +import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.EncodingEnum; +import ca.uhn.fhir.util.ParametersUtil; + +public class ValidateMethodBindingDstu3 extends OperationMethodBinding { + + public ValidateMethodBindingDstu3(Class theReturnResourceType, Class theReturnTypeFromRp, Method theMethod, FhirContext theContext, Object theProvider, + Validate theAnnotation) { + super(theReturnResourceType, theReturnTypeFromRp, theMethod, theContext, theProvider, true, Constants.EXTOP_VALIDATE, theAnnotation.type(), new OperationParam[0], BundleTypeEnum.COLLECTION); + + List newParams = new ArrayList(); + int idx = 0; + for (IParameter next : getParameters()) { + if (next instanceof ResourceParameter) { + if (IBaseResource.class.isAssignableFrom(((ResourceParameter) next).getResourceType())) { + Class parameterType = theMethod.getParameterTypes()[idx]; + if (String.class.equals(parameterType) || EncodingEnum.class.equals(parameterType)) { + newParams.add(next); + } else { + OperationParameter parameter = new OperationParameter(theContext, Constants.EXTOP_VALIDATE, Constants.EXTOP_VALIDATE_RESOURCE, 0, 1); + parameter.initializeTypes(theMethod, null, null, parameterType); + newParams.add(parameter); + } + } else { + newParams.add(next); + } + } else { + newParams.add(next); + } + idx++; + } + setParameters(newParams); + + } + + + public static BaseHttpClientInvocation createValidateInvocation(FhirContext theContext, IBaseResource theResource) { + IBaseParameters parameters = (IBaseParameters) theContext.getResourceDefinition("Parameters").newInstance(); + ParametersUtil.addParameterToParameters(theContext, parameters, theResource, "resource"); + + String resourceName = theContext.getResourceDefinition(theResource).getName(); + String resourceId = theResource.getIdElement().getIdPart(); + + BaseHttpClientInvocation retVal = createOperationInvocation(theContext, resourceName, resourceId, Constants.EXTOP_VALIDATE, parameters, false); + return retVal; + } + + +} diff --git a/hapi-fhir-jaxrsserver-base/pom.xml b/hapi-fhir-jaxrsserver-base/pom.xml index f8643f80eeb..df4a15d0587 100644 --- a/hapi-fhir-jaxrsserver-base/pom.xml +++ b/hapi-fhir-jaxrsserver-base/pom.xml @@ -40,6 +40,11 @@ hapi-fhir-structures-dstu2 1.6-SNAPSHOT + + ca.uhn.hapi.fhir + hapi-fhir-structures-dstu3 + 1.6-SNAPSHOT + javax.ws.rs diff --git a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java index 24d29ab438b..fd34c238c80 100644 --- a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java +++ b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java @@ -39,12 +39,16 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.apache.commons.lang3.StringUtils; +import org.hl7.fhir.dstu3.hapi.rest.server.ServerConformanceProvider; +import org.hl7.fhir.dstu3.model.Conformance; +import org.hl7.fhir.instance.model.api.IBaseResource; import org.slf4j.LoggerFactory; import ca.uhn.fhir.context.ConfigurationException; +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest.Builder; -import ca.uhn.fhir.model.dstu2.resource.Conformance; import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum; @@ -56,7 +60,6 @@ import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.IRestfulResponse; import ca.uhn.fhir.rest.server.ResourceBinding; import ca.uhn.fhir.rest.server.RestulfulServerConfiguration; -import ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider; import ca.uhn.fhir.util.ReflectionUtil; /** @@ -78,7 +81,8 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv private RestulfulServerConfiguration serverConfiguration = new RestulfulServerConfiguration(); /** the conformance. It is created once during startup */ - private Conformance myConformance; + private Conformance myDstu3Conformance; + private ca.uhn.fhir.model.dstu2.resource.Conformance myDstu2Conformance; /** * Constructor allowing the description, servername and server to be set @@ -92,6 +96,21 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv serverConfiguration.setServerName(StringUtils.defaultIfEmpty(serverName, "")); serverConfiguration.setServerVersion(StringUtils.defaultIfEmpty(serverVersion, "")); } + + /** + * Constructor allowing the description, servername and server to be set + * @param ctx the {@link FhirContext} instance. + * @param implementationDescription the implementation description. If null, "" is used + * @param serverName the server name. If null, "" is used + * @param serverVersion the server version. If null, "" is used + */ + protected AbstractJaxRsConformanceProvider(FhirContext ctx, String implementationDescription, String serverName, String serverVersion) { + super(ctx); + serverConfiguration.setFhirContext(ctx); + serverConfiguration.setImplementationDescription(StringUtils.defaultIfEmpty(implementationDescription, "")); + serverConfiguration.setServerName(StringUtils.defaultIfEmpty(serverName, "")); + serverConfiguration.setServerVersion(StringUtils.defaultIfEmpty(serverVersion, "")); + } /** * This method will set the conformance during the postconstruct phase. The @@ -112,9 +131,15 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv HardcodedServerAddressStrategy hardcodedServerAddressStrategy = new HardcodedServerAddressStrategy(); hardcodedServerAddressStrategy.setValue(getBaseForServer()); serverConfiguration.setServerAddressStrategy(hardcodedServerAddressStrategy); - ServerConformanceProvider serverConformanceProvider = new ServerConformanceProvider(serverConfiguration); - serverConformanceProvider.initializeOperations(); - myConformance = serverConformanceProvider.getServerConformance(null); + if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU3)) { + ServerConformanceProvider serverConformanceProvider = new ServerConformanceProvider(serverConfiguration); + serverConformanceProvider.initializeOperations(); + myDstu3Conformance = serverConformanceProvider.getServerConformance(null); + } else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2)) { + ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider serverConformanceProvider = new ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider(serverConfiguration); + serverConformanceProvider.initializeOperations(); + myDstu2Conformance = serverConformanceProvider.getServerConformance(null); + } } /** @@ -145,7 +170,12 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv Builder request = getRequest(RequestTypeEnum.OPTIONS, RestOperationTypeEnum.METADATA); IRestfulResponse response = request.build().getResponse(); response.addHeader(Constants.HEADER_CORS_ALLOW_ORIGIN, "*"); - return (Response) response.returnResponse(ParseAction.create(myConformance), Constants.STATUS_HTTP_200_OK, true, null, getResourceType().getSimpleName()); + if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU3)) { + return (Response) response.returnResponse(ParseAction.create(myDstu3Conformance), Constants.STATUS_HTTP_200_OK, true, null, getResourceType().getSimpleName()); + } else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2)) { + return (Response) response.returnResponse(ParseAction.create(myDstu2Conformance), Constants.STATUS_HTTP_200_OK, true, null, getResourceType().getSimpleName()); + } + return (Response) response.returnResponse(null, Constants.STATUS_HTTP_500_INTERNAL_ERROR, true, null, getResourceType().getSimpleName()); } /** @@ -217,9 +247,15 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv return count; } + @SuppressWarnings("unchecked") @Override - public Class getResourceType() { - return Conformance.class; + public Class getResourceType() { + if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU3)) { + return Class.class.cast(Conformance.class); + } else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2)) { + return Class.class.cast(ca.uhn.fhir.model.dstu2.resource.Conformance.class); + } + return null; } } diff --git a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsPageProvider.java b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsPageProvider.java index 6de4af611ed..0da2522045d 100644 --- a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsPageProvider.java +++ b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsPageProvider.java @@ -31,6 +31,7 @@ import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor; import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsResponseException; import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest; @@ -65,6 +66,19 @@ public abstract class AbstractJaxRsPageProvider extends AbstractJaxRsProvider im } } + /** + * Provides the ability to set the {@link FhirContext} instance. + * @param ctx the {@link FhirContext} instance. + */ + protected AbstractJaxRsPageProvider(FhirContext ctx) { + super(ctx); + try { + myBinding = new PageMethodBinding(getFhirContext(), PageProvider.class.getMethod("getPage")); + } catch (Exception e) { + throw new ca.uhn.fhir.context.ConfigurationException(e); + } + } + @Override public String getBaseForRequest() { try { diff --git a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProvider.java b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProvider.java index 3cf0b43067a..d5a52771419 100644 --- a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProvider.java +++ b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProvider.java @@ -53,8 +53,7 @@ import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; */ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults { - /** a static initialization for the fhircontext. Only DSTU2 is supported */ - private static final FhirContext CTX = FhirContext.forDstu2(); + private final FhirContext CTX; /** the uri info */ @Context @@ -67,7 +66,22 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults { public FhirContext getFhirContext() { return CTX; } + + /** + * Default is DSTU2. Use {@link AbstractJaxRsProvider#AbstractJaxRsProvider(FhirContext)} to specify a DSTU3 context. + */ + protected AbstractJaxRsProvider() { + CTX = FhirContext.forDstu2(); + } + /** + * + * @param ctx the {@link FhirContext} to support. + */ + protected AbstractJaxRsProvider(FhirContext ctx) { + CTX = ctx; + } + /** * This method returns the query parameters * @return the query parameters diff --git a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProvider.java b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProvider.java index 91b76b1160c..204b9e39e33 100644 --- a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProvider.java +++ b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProvider.java @@ -22,8 +22,6 @@ package ca.uhn.fhir.jaxrs.server; import java.io.IOException; import java.net.URL; -import java.util.Collections; -import java.util.List; import javax.interceptor.Interceptors; import javax.ws.rs.Consumes; @@ -37,12 +35,14 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import org.hl7.fhir.instance.model.api.IBaseResource; + +import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor; import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsResponseException; import ca.uhn.fhir.jaxrs.server.util.JaxRsMethodBindings; import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest; import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest.Builder; -import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.method.BaseMethodBinding; @@ -51,7 +51,6 @@ import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.IPagingProvider; import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.IRestfulServer; -import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; /** * This server is the abstract superclass for all resource providers. It exposes @@ -62,7 +61,7 @@ import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; @Consumes({ MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML }) @Interceptors(JaxRsExceptionInterceptor.class) -public abstract class AbstractJaxRsResourceProvider extends AbstractJaxRsProvider +public abstract class AbstractJaxRsResourceProvider extends AbstractJaxRsProvider implements IRestfulServer, IResourceProvider { /** the method bindings for this class */ @@ -73,9 +72,19 @@ public abstract class AbstractJaxRsResourceProvider extends * being constructed. */ protected AbstractJaxRsResourceProvider() { + super(); theBindings = JaxRsMethodBindings.getMethodBindings(this, getClass()); } + /** + * Provides the ability to specify the {@link FhirContext}. + * @param ctx the {@link FhirContext} instance. + */ + protected AbstractJaxRsResourceProvider(FhirContext ctx) { + super(ctx); + theBindings = JaxRsMethodBindings.getMethodBindings(this, getClass()); + } + /** * This constructor takes in an explicit interface class. This subclass * should be identical to the class being constructed but is given @@ -85,9 +94,24 @@ public abstract class AbstractJaxRsResourceProvider extends * @param theProviderClass the interface of the class */ protected AbstractJaxRsResourceProvider(Class theProviderClass) { + super(); theBindings = JaxRsMethodBindings.getMethodBindings(this, theProviderClass); } + /** + * This constructor takes in an explicit interface class. This subclass + * should be identical to the class being constructed but is given + * explicitly in order to avoid issues with proxy classes in a jee + * environment. + * + * @param ctx the {@link FhirContext} instance. + * @param theProviderClass the interface of the class + */ + protected AbstractJaxRsResourceProvider(FhirContext ctx, Class theProviderClass) { + super(ctx); + theBindings = JaxRsMethodBindings.getMethodBindings(this, theProviderClass); + } + /** * The base for request for a resource provider has the following form:
* {@link AbstractJaxRsResourceProvider#getBaseForServer() diff --git a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/util/JaxRsRequest.java b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/util/JaxRsRequest.java index ffc806dcf29..46e0d3ecce7 100644 --- a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/util/JaxRsRequest.java +++ b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/util/JaxRsRequest.java @@ -31,7 +31,9 @@ import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import org.apache.commons.lang3.StringUtils; +import org.hl7.fhir.dstu3.model.IdType; +import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.jaxrs.server.AbstractJaxRsProvider; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.rest.api.RequestTypeEnum; @@ -129,18 +131,33 @@ public class JaxRsRequest extends RequestDetails { throw new InvalidRequestException("Don't know how to handle request path: " + myServer.getUriInfo().getRequestUri().toASCIIString()); } + + FhirVersionEnum fhirContextVersion = myServer.getFhirContext().getVersion().getVersion(); if (StringUtils.isNotBlank(myVersion)) { - result.setId( - new IdDt(myServer.getBaseForRequest(), UrlUtil.unescape(myId), UrlUtil.unescape(myVersion))); + if (FhirVersionEnum.DSTU3.equals(fhirContextVersion)) { + result.setId( + new IdType(myServer.getBaseForRequest(), UrlUtil.unescape(myId), UrlUtil.unescape(myVersion))); + } else if (FhirVersionEnum.DSTU2.equals(fhirContextVersion)) { + result.setId( + new IdDt(myServer.getBaseForRequest(), UrlUtil.unescape(myId), UrlUtil.unescape(myVersion))); + } } else if (StringUtils.isNotBlank(myId)) { - result.setId(new IdDt(myServer.getBaseForRequest(), UrlUtil.unescape(myId))); + if (FhirVersionEnum.DSTU3.equals(fhirContextVersion)) { + result.setId(new IdType(myServer.getBaseForRequest(), UrlUtil.unescape(myId))); + } else if (FhirVersionEnum.DSTU2.equals(fhirContextVersion)) { + result.setId(new IdDt(myServer.getBaseForRequest(), UrlUtil.unescape(myId))); + } } if (myRestOperation == RestOperationTypeEnum.UPDATE) { String contentLocation = result.getHeader(Constants.HEADER_CONTENT_LOCATION); if (contentLocation != null) { - result.setId(new IdDt(contentLocation)); + if (FhirVersionEnum.DSTU3.equals(fhirContextVersion)) { + result.setId(new IdType(contentLocation)); + } else if (FhirVersionEnum.DSTU2.equals(fhirContextVersion)) { + result.setId(new IdDt(contentLocation)); + } } } diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/client/GenericJaxRsClientDstu3Test.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/client/GenericJaxRsClientDstu3Test.java new file mode 100644 index 00000000000..ae226b5203f --- /dev/null +++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/client/GenericJaxRsClientDstu3Test.java @@ -0,0 +1,2207 @@ +package ca.uhn.fhir.jaxrs.client; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.either; +import static org.hamcrest.Matchers.emptyString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.io.Charsets; +import org.apache.commons.io.IOUtils; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.hl7.fhir.dstu3.model.Bundle; +import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent; +import org.hl7.fhir.dstu3.model.Bundle.BundleLinkComponent; +import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb; +import org.hl7.fhir.dstu3.model.CodeType; +import org.hl7.fhir.dstu3.model.Conformance; +import org.hl7.fhir.dstu3.model.DateType; +import org.hl7.fhir.dstu3.model.IdType; +import org.hl7.fhir.dstu3.model.Identifier; +import org.hl7.fhir.dstu3.model.InstantType; +import org.hl7.fhir.dstu3.model.Meta; +import org.hl7.fhir.dstu3.model.Observation; +import org.hl7.fhir.dstu3.model.OperationOutcome; +import org.hl7.fhir.dstu3.model.Parameters; +import org.hl7.fhir.dstu3.model.Patient; +import org.hl7.fhir.dstu3.model.StringType; +import org.hl7.fhir.dstu3.model.UriType; +import org.hl7.fhir.instance.model.api.IBase; +import org.hl7.fhir.instance.model.api.IBaseBundle; +import org.hl7.fhir.instance.model.api.IBaseOperationOutcome; +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 com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.jaxrs.client.JaxRsRestfulClientFactory; +import ca.uhn.fhir.jaxrs.server.test.RandomServerPortProvider; +import ca.uhn.fhir.model.api.Include; +import ca.uhn.fhir.model.primitive.UriDt; +import ca.uhn.fhir.parser.IParser; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.api.PreferReturnEnum; +import ca.uhn.fhir.rest.api.SummaryEnum; +import ca.uhn.fhir.rest.client.IGenericClient; +import ca.uhn.fhir.rest.client.ServerValidationModeEnum; +import ca.uhn.fhir.rest.client.api.Header; +import ca.uhn.fhir.rest.client.exceptions.InvalidResponseException; +import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; +import ca.uhn.fhir.rest.method.SearchStyleEnum; +import ca.uhn.fhir.rest.param.DateRangeParam; +import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.EncodingEnum; + +public class GenericJaxRsClientDstu3Test { + private static FhirContext ourCtx; + private static int ourPort; + private static Server ourServer; + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(GenericJaxRsClientDstu3Test.class); + private static int ourResponseCount = 0; + private static String[] ourResponseBodies; + private static String ourResponseBody; + private static String ourResponseContentType; + private static int ourResponseStatus; + private static String ourRequestUri; + + @Before + public void before() { + JaxRsRestfulClientFactory clientFactory = new JaxRsRestfulClientFactory(ourCtx); + clientFactory.setServerValidationMode(ServerValidationModeEnum.NEVER); + + ourCtx.setRestfulClientFactory(clientFactory); + ourResponseCount = 0; + } + + private String getPatientFeedWithOneResult() { + //@formatter:off + String msg = "\n" + + "d039f91a-cc3c-4013-988e-af4d8d0614bd\n" + + "\n" + + "" + + "" + + "
John Cardinal: 444333333
" + + "" + + "" + + "" + + "" + + "
" + + "
" + + "
\n" + + "
\n" + + "
"; + //@formatter:on + return msg; + } + + @Test + public void testAcceptHeaderFetchConformance() throws Exception { + IParser p = ourCtx.newXmlParser(); + + Conformance conf = new Conformance(); + conf.setCopyright("COPY"); + + final String respString = p.encodeResourceToString(conf); + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = respString; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + + client.fetchConformance().ofType(Conformance.class).execute(); + assertEquals("http://localhost:" + ourPort + "/fhir/metadata", ourRequestUri); + assertEquals(1, ourRequestHeaders.get("Accept").size()); + assertThat(ourRequestHeaders.get("Accept").get(0).getValue(), containsString(Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON)); + + + client.fetchConformance().ofType(Conformance.class).encodedJson().execute(); + assertEquals("http://localhost:" + ourPort + "/fhir/metadata?_format=json", ourRequestUri); + assertEquals(1, ourRequestHeaders.get("Accept").size()); + assertThat(ourRequestHeaders.get("Accept").get(0).getValue(), containsString(Constants.CT_FHIR_JSON)); + + + client.fetchConformance().ofType(Conformance.class).encodedXml().execute(); + assertEquals("http://localhost:" + ourPort + "/fhir/metadata?_format=xml", ourRequestUri); + assertEquals(1, ourRequestHeaders.get("Accept").size()); + assertThat(ourRequestHeaders.get("Accept").get(0).getValue(), containsString(Constants.CT_FHIR_XML)); + + } + + @Test + public void testAcceptHeaderPreflightConformance() throws Exception { + final IParser p = ourCtx.newXmlParser(); + + final Conformance conf = new Conformance(); + conf.setCopyright("COPY"); + + final Patient patient = new Patient(); + patient.addName().addFamily("FAMILY"); + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBodies = new String[] { p.encodeResourceToString(conf), p.encodeResourceToString(patient) }; + + ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE); + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + Patient resp = client.read(Patient.class, new IdType("123").getValue()); + assertEquals("FAMILY", resp.getName().get(0).getFamily().get(0).getValue()); + assertEquals("http://localhost:" + ourPort + "/fhir/metadata", ourRequestUriAll.get(0)); + assertEquals(1, ourRequestHeadersAll.get(0).get("Accept").size()); + assertThat(ourRequestHeadersAll.get(0).get("Accept").get(0).getValue(), containsString(Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON)); + assertThat(ourRequestHeadersAll.get(0).get("Accept").get(0).getValue(), containsString(Constants.CT_FHIR_XML)); + assertThat(ourRequestHeadersAll.get(0).get("Accept").get(0).getValue(), containsString(Constants.CT_FHIR_JSON)); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123", ourRequestUriAll.get(1)); + assertEquals(1, ourRequestHeadersAll.get(1).get("Accept").size()); + assertThat(ourRequestHeadersAll.get(1).get("Accept").get(0).getValue(), containsString(Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON)); + assertThat(ourRequestHeadersAll.get(1).get("Accept").get(0).getValue(), containsString(Constants.CT_FHIR_XML)); + assertThat(ourRequestHeadersAll.get(1).get("Accept").get(0).getValue(), containsString(Constants.CT_FHIR_JSON)); + } + + @Test + public void testAcceptHeaderPreflightConformancePreferJson() throws Exception { + final IParser p = ourCtx.newXmlParser(); + + final Conformance conf = new Conformance(); + conf.setCopyright("COPY"); + + final Patient patient = new Patient(); + patient.addName().addFamily("FAMILY"); + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBodies = new String[] { p.encodeResourceToString(conf), p.encodeResourceToString(patient) }; + + ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE); + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + client.setEncoding(EncodingEnum.JSON); + + Patient resp = client.read(Patient.class, new IdType("123").getValue()); + assertEquals("FAMILY", resp.getName().get(0).getFamily().get(0).getValue()); + assertEquals("http://localhost:" + ourPort + "/fhir/metadata?_format=json", ourRequestUriAll.get(0)); + assertEquals(1, ourRequestHeadersAll.get(0).get("Accept").size()); + assertThat(ourRequestHeadersAll.get(0).get("Accept").get(0).getValue(), containsString(Constants.CT_FHIR_JSON)); + assertThat(ourRequestHeadersAll.get(0).get("Accept").get(0).getValue(), not(containsString(Constants.CT_FHIR_XML))); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123?_format=json", ourRequestUriAll.get(1)); + assertEquals(1, ourRequestHeadersAll.get(1).get("Accept").size()); + assertThat(ourRequestHeadersAll.get(1).get("Accept").get(0).getValue(), containsString(Constants.CT_FHIR_JSON)); + assertThat(ourRequestHeadersAll.get(1).get("Accept").get(0).getValue(), not(containsString(Constants.CT_FHIR_XML))); + } + + @Test + @SuppressWarnings("deprecation") + public void testConformance() throws Exception { + IParser p = ourCtx.newXmlParser(); + + Conformance conf = new Conformance(); + conf.setCopyright("COPY"); + + final String respString = p.encodeResourceToString(conf); + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = respString; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + + //@formatter:off + Conformance resp = (Conformance)client.conformance(); + + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/metadata", ourRequestUri); + assertEquals("COPY", resp.getCopyright()); + assertEquals("GET", ourRequestMethod); + + + } + + @Test + public void testProviderWhereWeForgotToSetTheContext() throws Exception { + JaxRsRestfulClientFactory clientFactory = new JaxRsRestfulClientFactory(); // no ctx + clientFactory.setServerValidationMode(ServerValidationModeEnum.NEVER); + + ourCtx.setRestfulClientFactory(clientFactory); + + try { + ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + fail(); + } catch (IllegalStateException e) { + assertEquals("JaxRsRestfulClientFactory does not have FhirContext defined. This must be set via JaxRsRestfulClientFactory#setFhirContext(FhirContext)", e.getMessage()); + } + } + + + @Test + public void testCreate() throws Exception { + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + + Patient p = new Patient(); + p.addName().addFamily("FOOFAMILY"); + + client.create().resource(p).execute(); + + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + assertThat(ourRequestBodyString, containsString("")); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient", ourRequestUri); + assertEquals("POST", ourRequestMethod); + + + p.setId("123"); + + client.create().resource(p).execute(); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + String body = ourRequestBodyString; + assertThat(body, containsString("")); + assertThat(body, not(containsString("123"))); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient", ourRequestUri); + assertEquals("POST", ourRequestMethod); + + + } + + @Test + public void testCreateConditional() throws Exception { + + + ourResponseStatus = Constants.STATUS_HTTP_204_NO_CONTENT; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + + Patient p = new Patient(); + p.addName().addFamily("FOOFAMILY"); + + client.create().resource(p).conditionalByUrl("Patient?name=foo").execute(); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + assertThat(ourRequestBodyString, containsString("")); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient", ourRequestUri); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=foo", ourRequestFirstHeaders.get(Constants.HEADER_IF_NONE_EXIST).getValue()); + assertEquals("POST", ourRequestMethod); + + + client.create().resource(p).conditionalByUrl("Patient?name=http://foo|bar").execute(); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + assertThat(ourRequestBodyString, containsString("")); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient", ourRequestUri); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=http%3A//foo%7Cbar", ourRequestFirstHeaders.get(Constants.HEADER_IF_NONE_EXIST).getValue()); + assertEquals("POST", ourRequestMethod); + + + client.create().resource(p).conditional().where(Patient.NAME.matches().value("foo")).execute(); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + assertThat(ourRequestBodyString, containsString("")); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient", ourRequestUri); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=foo", ourRequestFirstHeaders.get(Constants.HEADER_IF_NONE_EXIST).getValue()); + assertEquals("POST", ourRequestMethod); + + + } + + @SuppressWarnings("deprecation") + @Test + public void testCreateNonFluent() throws Exception { + ourResponseStatus = Constants.STATUS_HTTP_204_NO_CONTENT; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + + Patient p = new Patient(); + p.addName().addFamily("FOOFAMILY"); + + client.create(p); + + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + assertThat(ourRequestBodyString, containsString("")); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient", ourRequestUri); + assertEquals("POST", ourRequestMethod); + + } + + @Test + public void testCreatePrefer() throws Exception { + + + ourResponseStatus = Constants.STATUS_HTTP_204_NO_CONTENT; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + + Patient p = new Patient(); + p.addName().addFamily("FOOFAMILY"); + + client.create().resource(p).prefer(PreferReturnEnum.MINIMAL).execute(); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_PREFER).size()); + assertEquals(Constants.HEADER_PREFER_RETURN + '=' + Constants.HEADER_PREFER_RETURN_MINIMAL, ourRequestHeaders.get(Constants.HEADER_PREFER).get(0).getValue()); + + + client.create().resource(p).prefer(PreferReturnEnum.REPRESENTATION).execute(); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_PREFER).size()); + assertEquals(Constants.HEADER_PREFER_RETURN + '=' + Constants.HEADER_PREFER_RETURN_REPRESENTATION, ourRequestHeaders.get(Constants.HEADER_PREFER).get(0).getValue()); + + + } + + @Test + public void testCreateReturningResourceBody() throws Exception { + Patient p = new Patient(); + p.setId("123"); + final String formatted = ourCtx.newXmlParser().encodeResourceToString(p); + + + + ourResponseStatus = Constants.STATUS_HTTP_200_OK; + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = formatted; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + p = new Patient(); + p.setId(new IdType("1")); + p.addName().addFamily("FOOFAMILY"); + + MethodOutcome output = client.create().resource(p).execute(); + assertNotNull(output.getResource()); + assertEquals("Patient/123", output.getResource().getIdElement().toUnqualifiedVersionless().getValue()); + } + + @Test + public void testDeleteConditional() throws Exception { + ourResponseStatus = Constants.STATUS_HTTP_204_NO_CONTENT; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + + client.delete().resourceById(new IdType("Patient/123")).execute(); + assertEquals("DELETE", ourRequestMethod); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123", ourRequestUri); + + + client.delete().resourceConditionalByUrl("Patient?name=foo").execute(); + assertEquals("DELETE", ourRequestMethod); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=foo", ourRequestUri); + + + client.delete().resourceConditionalByType("Patient").where(Patient.NAME.matches().value("foo")).execute(); + assertEquals("DELETE", ourRequestMethod); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=foo", ourRequestUri); + + + } + + @SuppressWarnings("deprecation") + @Test + public void testDeleteNonFluent() throws Exception { + ourResponseStatus = Constants.STATUS_HTTP_204_NO_CONTENT; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + + client.delete(Patient.class, new IdType("Patient/123").getValue()); + assertEquals("DELETE", ourRequestMethod); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123", ourRequestUri); + + + client.delete(Patient.class, "123"); + assertEquals("DELETE", ourRequestMethod); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123", ourRequestUri); + + + } + + @Test + public void testHistory() throws Exception { + + final String msg = getPatientFeedWithOneResult(); + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = msg; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + org.hl7.fhir.dstu3.model.Bundle response; + + //@formatter:off + response = client + .history() + .onServer() + .andReturnBundle(org.hl7.fhir.dstu3.model.Bundle.class) + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/_history", ourRequestUri); + assertEquals(1, response.getEntry().size()); + + + //@formatter:off + response = client + .history() + .onServer() + .andReturnBundle(org.hl7.fhir.dstu3.model.Bundle.class) + .since((Date)null) + .count(null) + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/_history", ourRequestUri); + assertEquals(1, response.getEntry().size()); + + + //@formatter:off + response = client + .history() + .onServer() + .andReturnBundle(org.hl7.fhir.dstu3.model.Bundle.class) + .since(new InstantType()) + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/_history", ourRequestUri); + assertEquals(1, response.getEntry().size()); + + + //@formatter:off + response = client + .history() + .onType(Patient.class) + .andReturnBundle(org.hl7.fhir.dstu3.model.Bundle.class) + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/_history", ourRequestUri); + assertEquals(1, response.getEntry().size()); + + + //@formatter:off + response = client + .history() + .onInstance(new IdType("Patient", "123")) + .andReturnBundle(org.hl7.fhir.dstu3.model.Bundle.class) + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/_history", ourRequestUri); + assertEquals(1, response.getEntry().size()); + + + //@formatter:off + response = client + .history() + .onInstance(new IdType("Patient", "123")) + .andReturnBundle(org.hl7.fhir.dstu3.model.Bundle.class) + .count(123) + .since(new InstantType("2001-01-02T11:22:33Z")) + .execute(); + //@formatter:on + assertThat(ourRequestUri, either(equalTo("http://localhost:" + ourPort + "/fhir/Patient/123/_history?_since=2001-01-02T11:22:33Z&_count=123")).or(equalTo("http://localhost:" + ourPort + "/fhir/Patient/123/_history?_count=123&_since=2001-01-02T11:22:33Z"))); + assertEquals(1, response.getEntry().size()); + + + //@formatter:off + response = client + .history() + .onInstance(new IdType("Patient", "123")) + .andReturnBundle(org.hl7.fhir.dstu3.model.Bundle.class) + .since(new InstantType("2001-01-02T11:22:33Z").getValue()) + .execute(); + //@formatter:on + assertThat(ourRequestUri, containsString("_since=2001-01")); + assertEquals(1, response.getEntry().size()); + + } + + @Test + public void testMetaAdd() throws Exception { + IParser p = ourCtx.newXmlParser(); + + Meta inMeta = new Meta().addProfile("urn:profile:in"); + + Parameters outParams = new Parameters(); + outParams.addParameter().setName("meta").setValue(new Meta().addProfile("urn:profile:out")); + final String respString = p.encodeResourceToString(outParams); + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = respString; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + + //@formatter:off + Meta resp = client + .meta() + .add() + .onResource(new IdType("Patient/123")) + .meta(inMeta) + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$meta-add", ourRequestUri); + assertEquals("urn:profile:out", resp.getProfile().get(0).getValue()); + assertEquals("POST", ourRequestMethod); + assertEquals("", ourRequestBodyString); + + + } + + @Test + public void testMetaGet() throws Exception { + IParser p = ourCtx.newXmlParser(); + + Parameters inParams = new Parameters(); + inParams.addParameter().setName("meta").setValue(new Meta().addProfile("urn:profile:in")); + + Parameters outParams = new Parameters(); + outParams.addParameter().setName("meta").setValue(new Meta().addProfile("urn:profile:out")); + final String respString = p.encodeResourceToString(outParams); + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = respString; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + + //@formatter:off + Meta resp = client + .meta() + .get(Meta.class) + .fromServer() + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/$meta", ourRequestUri); + assertEquals("urn:profile:out", resp.getProfile().get(0).getValue()); + assertEquals("GET", ourRequestMethod); + + + //@formatter:off + resp = client + .meta() + .get(Meta.class) + .fromType("Patient") + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$meta", ourRequestUri); + assertEquals("urn:profile:out", resp.getProfile().get(0).getValue()); + assertEquals("GET", ourRequestMethod); + + + //@formatter:off + resp = client + .meta() + .get(Meta.class) + .fromResource(new IdType("Patient/123")) + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$meta", ourRequestUri); + assertEquals("urn:profile:out", resp.getProfile().get(0).getValue()); + assertEquals("GET", ourRequestMethod); + + + } + + @Test + public void testOperationAsGetWithInParameters() throws Exception { + IParser p = ourCtx.newXmlParser(); + + Parameters inParams = new Parameters(); + inParams.addParameter().setName("param1").setValue(new StringType("STRINGVALIN1")); + inParams.addParameter().setName("param1").setValue(new StringType("STRINGVALIN1b")); + inParams.addParameter().setName("param2").setValue(new StringType("STRINGVALIN2")); + + Parameters outParams = new Parameters(); + outParams.addParameter().setValue(new StringType("STRINGVALOUT1")); + outParams.addParameter().setValue(new StringType("STRINGVALOUT2")); + final String respString = p.encodeResourceToString(outParams); + + + + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = respString; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + + //@formatter:off + Parameters resp = client + .operation() + .onServer() + .named("$SOMEOPERATION") + .withParameters(inParams) + .useHttpGet() + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION?param1=STRINGVALIN1¶m1=STRINGVALIN1b¶m2=STRINGVALIN2", ourRequestUri); + assertEquals(respString, p.encodeResourceToString(resp)); + assertEquals("GET", ourRequestMethod); + + + //@formatter:off + resp = client + .operation() + .onType(Patient.class) + .named("$SOMEOPERATION") + .withParameters(inParams) + .useHttpGet() + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$SOMEOPERATION?param1=STRINGVALIN1¶m1=STRINGVALIN1b¶m2=STRINGVALIN2", ourRequestUri); + assertEquals(respString, p.encodeResourceToString(resp)); + assertEquals("GET", ourRequestMethod); + + + //@formatter:off + resp = client + .operation() + .onInstance(new IdType("Patient", "123")) + .named("$SOMEOPERATION") + .withParameters(inParams) + .useHttpGet() + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$SOMEOPERATION?param1=STRINGVALIN1¶m1=STRINGVALIN1b¶m2=STRINGVALIN2", ourRequestUri); + assertEquals(respString, p.encodeResourceToString(resp)); + assertEquals("GET", ourRequestMethod); + + + // @formatter:off + resp = client + .operation() + .onInstance(new IdType("http://foo.com/bar/baz/Patient/123/_history/22")) + .named("$SOMEOPERATION") + .withParameters(inParams) + .useHttpGet() + .execute(); + // @formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$SOMEOPERATION?param1=STRINGVALIN1¶m1=STRINGVALIN1b¶m2=STRINGVALIN2", ourRequestUri); + + } + + @Test + public void testOperationAsGetWithNoInParameters() throws Exception { + IParser p = ourCtx.newXmlParser(); + + Parameters outParams = new Parameters(); + outParams.addParameter().setValue(new StringType("STRINGVALOUT1")); + outParams.addParameter().setValue(new StringType("STRINGVALOUT2")); + final String respString = p.encodeResourceToString(outParams); + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = respString; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + + //@formatter:off + Parameters resp = client + .operation() + .onServer() + .named("$SOMEOPERATION") + .withNoParameters(Parameters.class) + .useHttpGet() + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri); + assertEquals(respString, p.encodeResourceToString(resp)); + assertEquals("GET", ourRequestMethod); + + + //@formatter:off + resp = client + .operation() + .onType(Patient.class) + .named("$SOMEOPERATION") + .withNoParameters(Parameters.class) + .useHttpGet() + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$SOMEOPERATION", ourRequestUri); + assertEquals(respString, p.encodeResourceToString(resp)); + assertEquals("GET", ourRequestMethod); + + + //@formatter:off + resp = client + .operation() + .onInstance(new IdType("Patient", "123")) + .named("$SOMEOPERATION") + .withNoParameters(Parameters.class) + .useHttpGet() + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$SOMEOPERATION", ourRequestUri); + assertEquals(respString, p.encodeResourceToString(resp)); + assertEquals("GET", ourRequestMethod); + + + // @formatter:off + resp = client + .operation() + .onInstance(new IdType("http://foo.com/bar/baz/Patient/123/_history/22")) + .named("$SOMEOPERATION") + .withNoParameters(Parameters.class) + .useHttpGet() + .execute(); + // @formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$SOMEOPERATION", ourRequestUri); + + } + + @Test + public void testOperationWithBundleResponseJson() throws Exception { + + ourResponseContentType = Constants.CT_FHIR_JSON; + final String respString = "{\n" + " \"resourceType\":\"Bundle\",\n" + " \"id\":\"8cef5f2a-0ba9-43a5-be26-c8dde9ff0e19\",\n" + " \"base\":\"http://localhost:" + ourPort + "/fhir\"\n" + "}"; + ourResponseBody = respString; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + client.registerInterceptor(new LoggingInterceptor(true)); + + // Create the input parameters to pass to the server + Parameters inParams = new Parameters(); + inParams.addParameter().setName("start").setValue(new DateType("2001-01-01")); + inParams.addParameter().setName("end").setValue(new DateType("2015-03-01")); + + // Invoke $everything on "Patient/1" + Parameters outParams = client.operation().onInstance(new IdType("Patient", "18066")).named("$everything").withParameters(inParams).execute(); + + /* + * Note that the $everything operation returns a Bundle instead of a Parameters resource. The client operation + * methods return a Parameters instance however, so HAPI creates a Parameters object + * with a single parameter containing the value. + */ + org.hl7.fhir.dstu3.model.Bundle responseBundle = (org.hl7.fhir.dstu3.model.Bundle) outParams.getParameter().get(0).getResource(); + + // Print the response bundle + assertEquals("8cef5f2a-0ba9-43a5-be26-c8dde9ff0e19", responseBundle.getId()); + } + + @Test + public void testOperationWithBundleResponseXml() throws Exception { + IParser p = ourCtx.newXmlParser(); + + Parameters inParams = new Parameters(); + inParams.addParameter().setValue(new StringType("STRINGVALIN1")); + inParams.addParameter().setValue(new StringType("STRINGVALIN2")); + String reqString = p.encodeResourceToString(inParams); + + org.hl7.fhir.dstu3.model.Bundle outParams = new org.hl7.fhir.dstu3.model.Bundle(); + outParams.setTotal(123); + final String respString = p.encodeResourceToString(outParams); + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = respString; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + + //@formatter:off + Parameters resp = client + .operation() + .onServer() + .named("$SOMEOPERATION") + .withParameters(inParams).execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + assertEquals(ourRequestBodyString, reqString); + assertEquals("POST", ourRequestMethod); + assertEquals(1, resp.getParameter().size()); + assertEquals(org.hl7.fhir.dstu3.model.Bundle.class, resp.getParameter().get(0).getResource().getClass()); + + } + + @Test + public void testOperationWithInlineParams() throws Exception { + IParser p = ourCtx.newXmlParser(); + + Parameters outParams = new Parameters(); + outParams.addParameter().setValue(new StringType("STRINGVALOUT1")); + outParams.addParameter().setValue(new StringType("STRINGVALOUT2")); + final String respString = p.encodeResourceToString(outParams); + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = respString; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + + //@formatter:off + Parameters resp = client + .operation() + .onServer() + .named("$SOMEOPERATION") + .withParameter(Parameters.class, "name1", new StringType("value1")) + .andParameter("name2", new StringType("value1")) + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri); + assertEquals(respString, p.encodeResourceToString(resp)); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + assertEquals("POST", ourRequestMethod); + assertEquals("", (ourRequestBodyString)); + + + /* + * Composite type + */ + + //@formatter:off + resp = client + .operation() + .onServer() + .named("$SOMEOPERATION") + .withParameter(Parameters.class, "name1", new Identifier().setSystem("system1").setValue("value1")) + .andParameter("name2", new StringType("value1")) + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri); + assertEquals(respString, p.encodeResourceToString(resp)); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + assertEquals("POST", ourRequestMethod); + assertEquals("", + (ourRequestBodyString)); + + + /* + * Resource + */ + + //@formatter:off + resp = client + .operation() + .onServer() + .named("$SOMEOPERATION") + .withParameter(Parameters.class, "name1", new Identifier().setSystem("system1").setValue("value1")) + .andParameter("name2", new Patient().setActive(true)) + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri); + assertEquals(respString, p.encodeResourceToString(resp)); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + assertEquals("POST", ourRequestMethod); + assertEquals( + "", + (ourRequestBodyString)); + + + } + + @Test(expected = IllegalArgumentException.class) + public void testOperationWithInvalidParam() { + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + // Who knows what the heck this is! + IBase weirdBase = new IBase() { + private static final long serialVersionUID = 1L; + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public boolean hasFormatComment() { + return false; + } + + @Override + public List getFormatCommentsPre() { + return null; + } + + @Override + public List getFormatCommentsPost() { + return null; + } + }; + + //@formatter:off + client + .operation() + .onServer() + .named("$SOMEOPERATION") + .withParameter(Parameters.class, "name1", weirdBase) + .execute(); + //@formatter:on + } + + @Test + public void testOperationWithProfiledDatatypeParam() throws IOException, Exception { + IParser p = ourCtx.newXmlParser(); + + Parameters outParams = new Parameters(); + outParams.addParameter().setValue(new StringType("STRINGVALOUT1")); + outParams.addParameter().setValue(new StringType("STRINGVALOUT2")); + final String respString = p.encodeResourceToString(outParams); + + + + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = respString; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + + //@formatter:off + client + .operation() + .onInstance(new IdType("http://foo/Patient/1")) + .named("validate-code") + .withParameter(Parameters.class, "code", new CodeType("8495-4")) + .andParameter("system", new UriType("http://loinc.org")) + .useHttpGet() + .execute(); + //@formatter:off + + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/1/$validate-code?code=8495-4&system=http%3A%2F%2Floinc.org", ourRequestUri); + + //@formatter:off + + client + .operation() + .onInstance(new IdType("http://foo/Patient/1")) + .named("validate-code") + .withParameter(Parameters.class, "code", new CodeType("8495-4")) + .andParameter("system", new UriType("http://loinc.org")) + .execute(); + //@formatter:off + + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/1/$validate-code", ourRequestUri); + ourLog.info(ourRequestBodyString); + assertEquals("",ourRequestBodyString); + + } + + @Test + public void testOperationWithListOfParameterResponse() throws Exception { + IParser p = ourCtx.newXmlParser(); + + Parameters inParams = new Parameters(); + inParams.addParameter().setValue(new StringType("STRINGVALIN1")); + inParams.addParameter().setValue(new StringType("STRINGVALIN2")); + String reqString = p.encodeResourceToString(inParams); + + Parameters outParams = new Parameters(); + outParams.addParameter().setValue(new StringType("STRINGVALOUT1")); + outParams.addParameter().setValue(new StringType("STRINGVALOUT2")); + final String respString = p.encodeResourceToString(outParams); + + + + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = respString; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + + //@formatter:off + Parameters resp = client + .operation() + .onServer() + .named("$SOMEOPERATION") + .withParameters(inParams).execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri); + assertEquals(respString, p.encodeResourceToString(resp)); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + assertEquals(ourRequestBodyString, reqString); + assertEquals("POST", ourRequestMethod); + + + //@formatter:off + resp = client + .operation() + .onType(Patient.class) + .named("$SOMEOPERATION") + .withParameters(inParams).execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$SOMEOPERATION", ourRequestUri); + assertEquals(respString, p.encodeResourceToString(resp)); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + assertEquals(ourRequestBodyString, reqString); + assertEquals("POST", ourRequestMethod); + + + //@formatter:off + resp = client + .operation() + .onInstance(new IdType("Patient", "123")) + .named("$SOMEOPERATION") + .withParameters(inParams).execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$SOMEOPERATION", ourRequestUri); + assertEquals(respString, p.encodeResourceToString(resp)); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + assertEquals(ourRequestBodyString, reqString); + assertEquals("POST", ourRequestMethod); + + + resp = client.operation().onInstance(new IdType("http://foo.com/bar/baz/Patient/123/_history/22")).named("$SOMEOPERATION").withParameters(inParams).execute(); + // @formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$SOMEOPERATION", ourRequestUri); + + } + + @Test + public void testOperationWithNoInParameters() throws Exception { + IParser p = ourCtx.newXmlParser(); + + Parameters inParams = new Parameters(); + final String reqString = p.encodeResourceToString(inParams); + + Parameters outParams = new Parameters(); + outParams.addParameter().setValue(new StringType("STRINGVALOUT1")); + outParams.addParameter().setValue(new StringType("STRINGVALOUT2")); + final String respString = p.encodeResourceToString(outParams); + + + + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = respString; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + + //@formatter:off + Parameters resp = client + .operation() + .onServer() + .named("$SOMEOPERATION") + .withNoParameters(Parameters.class).execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/$SOMEOPERATION", ourRequestUri); + assertEquals(respString, p.encodeResourceToString(resp)); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + assertEquals(ourRequestBodyString, reqString); + assertEquals("POST", ourRequestMethod); + + + //@formatter:off + resp = client + .operation() + .onType(Patient.class) + .named("$SOMEOPERATION") + .withNoParameters(Parameters.class).execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$SOMEOPERATION", ourRequestUri); + assertEquals(respString, p.encodeResourceToString(resp)); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + assertEquals(ourRequestBodyString, reqString); + assertEquals("POST", ourRequestMethod); + + + //@formatter:off + resp = client + .operation() + .onInstance(new IdType("Patient", "123")) + .named("$SOMEOPERATION") + .withNoParameters(Parameters.class).execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$SOMEOPERATION", ourRequestUri); + assertEquals(respString, p.encodeResourceToString(resp)); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + assertEquals(ourRequestBodyString, reqString); + assertEquals("POST", ourRequestMethod); + + + // @formatter:off + resp = client + .operation() + .onInstance(new IdType("http://foo.com/bar/baz/Patient/123/_history/22")) + .named("$SOMEOPERATION") + .withNoParameters(Parameters.class) + .execute(); + // @formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123/$SOMEOPERATION", ourRequestUri); + + } + + @Test + public void testPageNext() throws Exception { + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = getPatientFeedWithOneResult(); + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + + org.hl7.fhir.dstu3.model.Bundle sourceBundle = new org.hl7.fhir.dstu3.model.Bundle(); + sourceBundle.getLinkOrCreate(IBaseBundle.LINK_PREV).setUrl("http://localhost:" + ourPort + "/fhir/prev"); + sourceBundle.getLinkOrCreate(IBaseBundle.LINK_NEXT).setUrl("http://localhost:" + ourPort + "/fhir/next"); + + //@formatter:off + org.hl7.fhir.dstu3.model.Bundle resp = client + .loadPage() + .next(sourceBundle) + .execute(); + //@formatter:on + + assertEquals(1, resp.getEntry().size()); + assertEquals("http://localhost:" + ourPort + "/fhir/next", ourRequestUri); + + + } + + @Test + public void testPageNextNoLink() throws Exception { + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + org.hl7.fhir.dstu3.model.Bundle sourceBundle = new org.hl7.fhir.dstu3.model.Bundle(); + try { + client.loadPage().next(sourceBundle).execute(); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage(), containsString("Can not perform paging operation because no link was found in Bundle with relation \"next\"")); + } + } + + @Test + public void testPagePrev() throws Exception { + + + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = getPatientFeedWithOneResult(); + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + + org.hl7.fhir.dstu3.model.Bundle sourceBundle = new org.hl7.fhir.dstu3.model.Bundle(); + sourceBundle.getLinkOrCreate("previous").setUrl("http://localhost:" + ourPort + "/fhir/prev"); + + //@formatter:off + org.hl7.fhir.dstu3.model.Bundle resp = client + .loadPage() + .previous(sourceBundle) + .execute(); + //@formatter:on + + assertEquals(1, resp.getEntry().size()); + assertEquals("http://localhost:" + ourPort + "/fhir/prev", ourRequestUri); + + + /* + * Try with "prev" instead of "previous" + */ + + sourceBundle = new org.hl7.fhir.dstu3.model.Bundle(); + sourceBundle.getLinkOrCreate("prev").setUrl("http://localhost:" + ourPort + "/fhir/prev"); + + //@formatter:off + resp = client + .loadPage() + .previous(sourceBundle) + .execute(); + //@formatter:on + + assertEquals(1, resp.getEntry().size()); + assertEquals("http://localhost:" + ourPort + "/fhir/prev", ourRequestUri); + + + } + + @Test + public void testReadByUri() throws Exception { + + Patient patient = new Patient(); + patient.addName().addFamily("FAM"); + final String respString = ourCtx.newXmlParser().encodeResourceToString(patient); + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = respString; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + Patient response; + + + response = (Patient) client.read(new UriDt("http://localhost:" + ourPort + "/fhir/Patient/123")); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123", ourRequestUri); + assertEquals("FAM", response.getName().get(0).getFamily().get(0).getValue()); + } + + @Test + public void testReadFluentByUri() throws Exception { + + Patient patient = new Patient(); + patient.addName().addFamily("FAM"); + final String respString = ourCtx.newXmlParser().encodeResourceToString(patient); + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = respString; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + Patient response; + + response = (Patient) client.read().resource(Patient.class).withUrl(new IdType("http://localhost:" + ourPort + "/AAA/Patient/123")).execute(); + assertEquals("http://localhost:" + ourPort + "/AAA/Patient/123", ourRequestUri); + assertEquals("FAM", response.getName().get(0).getFamily().get(0).getValue()); + } + + @Test + public void testReadUpdatedHeaderDoesntOverwriteResourceValue() throws Exception { + + //@formatter:off + final String input = "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + //@formatter:on + + + + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = input; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + org.hl7.fhir.dstu3.model.Bundle response; + + //@formatter:off + response = client + .search() + .forResource(Patient.class) + .returnBundle(org.hl7.fhir.dstu3.model.Bundle.class) + .execute(); + //@formatter:on + + // FIXME ? +// assertEquals("2015-06-22T15:48:57.554-04:00", response.getMeta().getLastUpdated().toString()); + assertEquals("Mon Jun 22 13:48:57 MDT 2015", response.getMeta().getLastUpdated().toString()); + } + + @Test + public void testReadWithElementsParam() throws Exception { + String msg = "{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}"; + + + + + ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8"; + ourResponseBody = msg; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + //@formatter:off + IBaseResource response = client.read() + .resource("Patient") + .withId("123") + .elementsSubset("name", "identifier") + .execute(); + //@formatter:on + + assertThat(ourRequestUri, either(equalTo("http://localhost:" + ourPort + "/fhir/Patient/123?_elements=name%2Cidentifier")).or(equalTo("http://localhost:" + ourPort + "/fhir/Patient/123?_elements=identifier%2Cname"))); + assertEquals(Patient.class, response.getClass()); + + } + + @Test + public void testReadWithSummaryInvalid() throws Exception { + String msg = "<>>>><<<<>"; + + + + + ourResponseContentType = Constants.CT_HTML + "; charset=UTF-8"; + ourResponseBody = msg; + + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + //@formatter:off + try { + client.read() + .resource(Patient.class) + .withId("123") + .summaryMode(SummaryEnum.TEXT) + .execute(); + fail(); + } catch (InvalidResponseException e) { + assertThat(e.getMessage(), containsString("Unable to Parse HTML - node")); + } + //@formatter:on + } + + @Test + public void testReadWithSummaryParamHtml() throws Exception { + String msg = "
HELP IM A DIV
"; + + + + + ourResponseContentType = Constants.CT_HTML + "; charset=UTF-8"; + ourResponseBody = msg; + + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + //@formatter:off + Patient response = client.read() + .resource(Patient.class) + .withId("123") + .summaryMode(SummaryEnum.TEXT) + .execute(); + //@formatter:on + + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123?_summary=text", ourRequestUri); + assertEquals(Patient.class, response.getClass()); + assertEquals("
HELP IM A DIV
", response.getText().getDiv().getValueAsString()); + + } + + @Test + public void testSearchByString() throws Exception { + String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}"; + + + + + ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8"; + ourResponseBody = msg; + + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + //@formatter:off + Bundle response = client.search() + .forResource("Patient") + .where(Patient.NAME.matches().value("james")) + .returnBundle(Bundle.class) + .execute(); + //@formatter:on + + assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=james", ourRequestUri); + assertEquals(Patient.class, response.getEntry().get(0).getResource().getClass()); + + } + + @Test + public void testSearchByUrl() throws Exception { + + final String msg = getPatientFeedWithOneResult(); + + + + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = msg; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + //@formatter:off + org.hl7.fhir.dstu3.model.Bundle response = client.search() + .byUrl("http://localhost:" + ourPort + "/AAA?name=http://foo|bar") + .encodedJson() + .returnBundle(org.hl7.fhir.dstu3.model.Bundle.class) + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/AAA?name=http%3A//foo%7Cbar&_format=json", ourRequestUri); + assertNotNull(response); + + + //@formatter:off + response = client.search() + .byUrl("Patient?name=http://foo|bar") + .encodedJson() + .returnBundle(org.hl7.fhir.dstu3.model.Bundle.class) + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=http%3A//foo%7Cbar&_format=json", ourRequestUri); + assertNotNull(response); + + + //@formatter:off + response = client.search() + .byUrl("/Patient?name=http://foo|bar") + .encodedJson() + .returnBundle(org.hl7.fhir.dstu3.model.Bundle.class) + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=http%3A//foo%7Cbar&_format=json", ourRequestUri); + assertNotNull(response); + + + //@formatter:off + response = client.search() + .byUrl("Patient") + .returnBundle(org.hl7.fhir.dstu3.model.Bundle.class) + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/Patient", ourRequestUri); + assertNotNull(response); + + + //@formatter:off + response = client.search() + .byUrl("Patient?") + .returnBundle(org.hl7.fhir.dstu3.model.Bundle.class) + .execute(); + //@formatter:on + assertEquals("http://localhost:" + ourPort + "/fhir/Patient", ourRequestUri); + assertNotNull(response); + + + try { + client.search().byUrl("foo/bar?test=1"); + } catch (IllegalArgumentException e) { + assertEquals("Search URL must be either a complete URL starting with http: or https:, or a relative FHIR URL in the form [ResourceType]?[Params]", e.getMessage()); + } + } + + /** + * See #191 + */ + @Test + public void testSearchReturningDstu2Bundle() throws Exception { + String msg = IOUtils.toString(GenericJaxRsClientDstu3Test.class.getResourceAsStream("/bundle_orion.xml")); + + + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = msg; + + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + //@formatter:off + org.hl7.fhir.dstu3.model.Bundle response = client.search() + .forResource("Observation") + .where(Patient.NAME.matches().value("FOO")) + .returnBundle(org.hl7.fhir.dstu3.model.Bundle.class) + .execute(); + //@formatter:on + + BundleLinkComponent link = response.getLink().get(0); + assertEquals("just trying add link", link.getRelation()); + assertEquals("blarion", link.getUrl()); + + BundleEntryComponent entry = response.getEntry().get(0); + link = entry.getLink().get(0); + assertEquals("orionhealth.edit", link.getRelation()); + assertEquals("Observation", link.getUrl()); + } + + @Test + public void testSearchWithElementsParam() throws Exception { + String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}"; + + + + + ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8"; + ourResponseBody = msg; + + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + //@formatter:off + Bundle response = client.search() + .forResource("Patient") + .where(Patient.NAME.matches().value("james")) + .elementsSubset("name", "identifier") + .returnBundle(Bundle.class) + .execute(); + //@formatter:on + + assertThat(ourRequestUri, either(equalTo("http://localhost:" + ourPort + "/fhir/Patient?name=james&_elements=name%2Cidentifier")).or(equalTo("http://localhost:" + ourPort + "/fhir/Patient?name=james&_elements=identifier%2Cname"))); + assertEquals(Patient.class, response.getEntry().get(0).getResource().getClass()); + + } + + @Test + public void testSearchByPost() throws Exception { + String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}"; + + + + + ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8"; + ourResponseBody = msg; + + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + //@formatter:off + Bundle response = client.search() + .forResource("Patient") + .where(Patient.NAME.matches().value("james")) + .elementsSubset("name", "identifier") + .usingStyle(SearchStyleEnum.POST) + .returnBundle(Bundle.class) + .execute(); + //@formatter:on + + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/_search?_elements=identifier%2Cname", ourRequestUri); + + // assertThat(ourRequestUri, + // either(equalTo("http://localhost:" + ourPort + "/fhir/Patient?name=james&_elements=name%2Cidentifier")).or(equalTo("http://localhost:" + ourPort + "/fhir/Patient?name=james&_elements=identifier%2Cname"))); + + assertEquals(Patient.class, response.getEntry().get(0).getResource().getClass()); + + assertEquals("name=james", ourRequestBodyString); + + assertEquals("application/x-www-form-urlencoded", ourRequestContentType.replace(";char", "; char").toLowerCase()); + assertEquals(Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON, ourRequestFirstHeaders.get("Accept").getValue()); + assertThat(ourRequestFirstHeaders.get("User-Agent").getValue(), not(emptyString())); + } + + @Test + public void testSearchByPostUseJson() throws Exception { + String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}"; + + + + + ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8"; + ourResponseBody = msg; + + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + //@formatter:off + Bundle response = client.search() + .forResource("Patient") + .where(Patient.NAME.matches().value("james")) + .elementsSubset("name", "identifier") + .usingStyle(SearchStyleEnum.POST) + .encodedJson() + .returnBundle(Bundle.class) + .execute(); + //@formatter:on + + assertThat(ourRequestUri, containsString("http://localhost:" + ourPort + "/fhir/Patient/_search?")); + assertThat(ourRequestUri, containsString("_elements=identifier%2Cname")); + assertThat(ourRequestUri, containsString("_format=json")); + + // assertThat(ourRequestUri, + // either(equalTo("http://localhost:" + ourPort + "/fhir/Patient?name=james&_elements=name%2Cidentifier")).or(equalTo("http://localhost:" + ourPort + "/fhir/Patient?name=james&_elements=identifier%2Cname"))); + + assertEquals(Patient.class, response.getEntry().get(0).getResource().getClass()); + + assertEquals("name=james", ourRequestBodyString); + + assertEquals("application/x-www-form-urlencoded", ourRequestContentType); + assertEquals(Constants.CT_FHIR_JSON, ourRequestFirstHeaders.get("Accept").getValue()); + } + + @Test + public void testSearchWithLastUpdated() throws Exception { + String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}"; + + + + + ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8"; + ourResponseBody = msg; + + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + //@formatter:off + Bundle response = client.search() + .forResource("Patient") + .where(Patient.NAME.matches().value("james")) + .lastUpdated(new DateRangeParam("2011-01-01", "2012-01-01")) + .returnBundle(Bundle.class) + .execute(); + //@formatter:on + + assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=james&_lastUpdated=ge2011-01-01&_lastUpdated=le2012-01-01", ourRequestUri); + assertEquals(Patient.class, response.getEntry().get(0).getResource().getClass()); + + } + + @Test + public void testSearchWithProfileAndSecurity() throws Exception { + String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}"; + + + + + ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8"; + ourResponseBody = msg; + + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + //@formatter:off + Bundle response = client.search() + .forResource("Patient") + .withProfile("http://foo1") + .withProfile("http://foo2") + .withSecurity("system1", "code1") + .withSecurity("system2", "code2") + .returnBundle(Bundle.class) + .execute(); + //@formatter:on + + assertEquals("http://localhost:" + ourPort + "/fhir/Patient?_security=system1%7Ccode1&_security=system2%7Ccode2&_profile=http%3A%2F%2Ffoo1&_profile=http%3A%2F%2Ffoo2", ourRequestUri); + assertEquals(Patient.class, response.getEntry().get(0).getResource().getClass()); + + } + + @SuppressWarnings("unused") + @Test + public void testSearchWithReverseInclude() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + + + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = msg; + + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + //@formatter:off + Bundle response = client.search() + .forResource(Patient.class) + .encodedJson() + .revInclude(new Include("Provenance:target")) + .returnBundle(Bundle.class) + .execute(); + //@formatter:on + + assertEquals("http://localhost:" + ourPort + "/fhir/Patient?_revinclude=Provenance%3Atarget&_format=json", ourRequestUri); + + } + + @Test + public void testSearchWithSummaryParam() throws Exception { + String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}"; + + + + + ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8"; + ourResponseBody = msg; + + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + //@formatter:off + Bundle response = client.search() + .forResource("Patient") + .where(Patient.NAME.matches().value("james")) + .summaryMode(SummaryEnum.FALSE) + .returnBundle(Bundle.class) + .execute(); + //@formatter:on + + assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=james&_summary=false", ourRequestUri); + assertEquals(Patient.class, response.getEntry().get(0).getResource().getClass()); + + } + + @Test + public void testTransactionWithListOfResources() throws Exception { + + org.hl7.fhir.dstu3.model.Bundle resp = new org.hl7.fhir.dstu3.model.Bundle(); + resp.addEntry().getResponse().setLocation("Patient/1/_history/1"); + resp.addEntry().getResponse().setLocation("Patient/2/_history/2"); + String respString = ourCtx.newJsonParser().encodeResourceToString(resp); + + + + + ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8"; + ourResponseBody = respString; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + List input = new ArrayList(); + + Patient p1 = new Patient(); // No ID + p1.addName().addFamily("PATIENT1"); + input.add(p1); + + Patient p2 = new Patient(); // Yes ID + p2.addName().addFamily("PATIENT2"); + p2.setId("Patient/2"); + input.add(p2); + + //@formatter:off + List response = client.transaction() + .withResources(input) + .encodedJson() + .execute(); + //@formatter:on + + assertEquals("http://localhost:" + ourPort + "/fhir?_format=json", ourRequestUri); + assertEquals(2, response.size()); + + String requestString = ourRequestBodyString; + org.hl7.fhir.dstu3.model.Bundle requestBundle = ourCtx.newJsonParser().parseResource(org.hl7.fhir.dstu3.model.Bundle.class, requestString); + assertEquals(2, requestBundle.getEntry().size()); + assertEquals(HTTPVerb.POST, requestBundle.getEntry().get(0).getRequest().getMethod()); + assertEquals(HTTPVerb.PUT, requestBundle.getEntry().get(1).getRequest().getMethod()); + assertEquals("Patient/2", requestBundle.getEntry().get(1).getRequest().getUrl()); + + p1 = (Patient) response.get(0); + assertEquals(new IdType("Patient/1/_history/1"), p1.getIdElement()); + // assertEquals("PATIENT1", p1.getName().get(0).getFamily().get(0).getValue()); + + p2 = (Patient) response.get(1); + assertEquals(new IdType("Patient/2/_history/2"), p2.getIdElement()); + // assertEquals("PATIENT2", p2.getName().get(0).getFamily().get(0).getValue()); + } + + @Test + public void testTransactionWithString() throws Exception { + + org.hl7.fhir.dstu3.model.Bundle req = new org.hl7.fhir.dstu3.model.Bundle(); + Patient patient = new Patient(); + patient.addName().addFamily("PAT_FAMILY"); + req.addEntry().setResource(patient); + Observation observation = new Observation(); + observation.getCode().setText("OBS_TEXT"); + req.addEntry().setResource(observation); + String reqString = ourCtx.newJsonParser().encodeResourceToString(req); + + org.hl7.fhir.dstu3.model.Bundle resp = new org.hl7.fhir.dstu3.model.Bundle(); + resp.addEntry().getResponse().setLocation("Patient/1/_history/1"); + resp.addEntry().getResponse().setLocation("Patient/2/_history/2"); + + + + + ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8"; + ourResponseBody = reqString; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + //@formatter:off + String response = client.transaction() + .withBundle(reqString) + .execute(); + //@formatter:on + + assertEquals("http://localhost:" + ourPort + "/fhir/", ourRequestUri); + assertThat(response, containsString("\"Bundle\"")); + assertEquals("application/json+fhir;charset=UTF-8", ourRequestFirstHeaders.get("Content-Type").getValue()); + + //@formatter:off + response = client.transaction() + .withBundle(reqString) + .encodedXml() + .execute(); + //@formatter:on + + assertEquals("http://localhost:" + ourPort + "/fhir/?_format=xml", ourRequestUri); + assertEquals("application/xml+fhir;charset=UTF-8", ourRequestFirstHeaders.get("Content-Type").getValue()); + + } + + @Test + public void testTransactionWithTransactionResource() throws Exception { + + org.hl7.fhir.dstu3.model.Bundle resp = new org.hl7.fhir.dstu3.model.Bundle(); + resp.addEntry().getResponse().setLocation("Patient/1/_history/1"); + resp.addEntry().getResponse().setLocation("Patient/2/_history/2"); + String respString = ourCtx.newJsonParser().encodeResourceToString(resp); + + + + + ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8"; + ourResponseBody = respString; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + org.hl7.fhir.dstu3.model.Bundle input = new org.hl7.fhir.dstu3.model.Bundle(); + + Patient p1 = new Patient(); // No ID + p1.addName().addFamily("PATIENT1"); + input.addEntry().setResource(p1); + + Patient p2 = new Patient(); // Yes ID + p2.addName().addFamily("PATIENT2"); + p2.setId("Patient/2"); + input.addEntry().setResource(p2); + + //@formatter:off + org.hl7.fhir.dstu3.model.Bundle response = client.transaction() + .withBundle(input) + .encodedJson() + .execute(); + //@formatter:on + + assertEquals("http://localhost:" + ourPort + "/fhir?_format=json", ourRequestUri); + assertEquals(2, response.getEntry().size()); + + assertEquals("Patient/1/_history/1", response.getEntry().get(0).getResponse().getLocation()); + assertEquals("Patient/2/_history/2", response.getEntry().get(1).getResponse().getLocation()); + } + + @Test + public void testUpdateConditional() throws Exception { + + + ourResponseStatus = Constants.STATUS_HTTP_204_NO_CONTENT; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + + Patient p = new Patient(); + p.addName().addFamily("FOOFAMILY"); + + client.update().resource(p).conditionalByUrl("Patient?name=foo").execute(); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + assertThat(ourRequestBodyString, containsString("")); + assertEquals("PUT", ourRequestMethod); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=foo", ourRequestUri); + + + client.update().resource(p).conditionalByUrl("Patient?name=http://foo|bar").execute(); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + assertThat(ourRequestBodyString, containsString("")); + assertEquals("PUT", ourRequestMethod); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=http%3A//foo%7Cbar", ourRequestUri); + + + client.update().resource(ourCtx.newXmlParser().encodeResourceToString(p)).conditionalByUrl("Patient?name=foo").execute(); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + assertThat(ourRequestBodyString, containsString("")); + assertEquals("PUT", ourRequestMethod); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=foo", ourRequestUri); + + + client.update().resource(p).conditional().where(Patient.NAME.matches().value("foo")).and(Patient.ADDRESS.matches().value("AAA|BBB")).execute(); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + assertThat(ourRequestBodyString, containsString("")); + assertEquals("PUT", ourRequestMethod); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=foo&address=AAA%5C%7CBBB", ourRequestUri); + + + client.update().resource(ourCtx.newXmlParser().encodeResourceToString(p)).conditional().where(Patient.NAME.matches().value("foo")).and(Patient.ADDRESS.matches().value("AAA|BBB")).execute(); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + assertThat(ourRequestBodyString, containsString("")); + assertEquals("PUT", ourRequestMethod); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient?name=foo&address=AAA%5C%7CBBB", ourRequestUri); + + + } + + @Test + public void testUpdateNonFluent() throws Exception { + + + ourResponseStatus = Constants.STATUS_HTTP_204_NO_CONTENT; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + + Patient p = new Patient(); + p.addName().addFamily("FOOFAMILY"); + + client.update(new IdType("Patient/123").getValue(), p); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + assertThat(ourRequestBodyString, containsString("")); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123", ourRequestUri); + assertEquals("PUT", ourRequestMethod); + + + client.update("123", p); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); + assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, ourRequestFirstHeaders.get(Constants.HEADER_CONTENT_TYPE).getValue().replace(";char", "; char")); + assertThat(ourRequestBodyString, containsString("")); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/123", ourRequestUri); + assertEquals("PUT", ourRequestMethod); + + } + + @Test + public void testUpdatePrefer() throws Exception { + + + ourResponseStatus = Constants.STATUS_HTTP_204_NO_CONTENT; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + + + Patient p = new Patient(); + p.setId(new IdType("1")); + p.addName().addFamily("FOOFAMILY"); + + client.update().resource(p).prefer(PreferReturnEnum.MINIMAL).execute(); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_PREFER).size()); + assertEquals(Constants.HEADER_PREFER_RETURN + '=' + Constants.HEADER_PREFER_RETURN_MINIMAL, ourRequestHeaders.get(Constants.HEADER_PREFER).get(0).getValue()); + + + client.update().resource(p).prefer(PreferReturnEnum.REPRESENTATION).execute(); + assertEquals(1, ourRequestHeaders.get(Constants.HEADER_PREFER).size()); + assertEquals(Constants.HEADER_PREFER_RETURN + '=' + Constants.HEADER_PREFER_RETURN_REPRESENTATION, ourRequestHeaders.get(Constants.HEADER_PREFER).get(0).getValue()); + + + } + + @Test + public void testUpdateReturningResourceBody() throws Exception { + Patient p = new Patient(); + p.setId("123"); + final String formatted = ourCtx.newXmlParser().encodeResourceToString(p); + + + + ourResponseStatus = Constants.STATUS_HTTP_200_OK; + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = formatted; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + p = new Patient(); + p.setId(new IdType("1")); + p.addName().addFamily("FOOFAMILY"); + + MethodOutcome output = client.update().resource(p).execute(); + assertNotNull(output.getResource()); + assertEquals("Patient/123", output.getResource().getIdElement().toUnqualifiedVersionless().getValue()); + } + + @Test + public void testValidateFluent() throws Exception { + + OperationOutcome oo = new OperationOutcome(); + oo.addIssue().setDiagnostics("FOOBAR"); + final String msg = ourCtx.newXmlParser().encodeResourceToString(oo); + + + + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = msg; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + Patient p = new Patient(); + p.addName().addGiven("GIVEN"); + + + MethodOutcome response; + + response = client.validate().resource(p).execute(); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$validate", ourRequestUri); + assertEquals("POST", ourRequestMethod); + assertEquals("", ourRequestBodyString); + assertNotNull(response.getOperationOutcome()); + assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssue().get(0).getDiagnosticsElement().getValue()); + + + response = client.validate().resource(ourCtx.newXmlParser().encodeResourceToString(p)).execute(); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$validate?_format=xml", ourRequestUri); + assertEquals("POST", ourRequestMethod); + assertEquals("", ourRequestBodyString); + assertNotNull(response.getOperationOutcome()); + assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssue().get(0).getDiagnosticsElement().getValue()); + + + response = client.validate().resource(ourCtx.newJsonParser().encodeResourceToString(p)).execute(); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$validate?_format=json", ourRequestUri); + assertEquals("POST", ourRequestMethod); + assertEquals("{\"resourceType\":\"Parameters\",\"parameter\":[{\"name\":\"resource\",\"resource\":{\"resourceType\":\"Patient\",\"name\":[{\"given\":[\"GIVEN\"]}]}}]}", ourRequestBodyString); + assertNotNull(response.getOperationOutcome()); + assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssue().get(0).getDiagnosticsElement().getValue()); + + + response = client.validate().resource(ourCtx.newJsonParser().encodeResourceToString(p)).prettyPrint().execute(); + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$validate?_format=json&_pretty=true", ourRequestUri); + assertEquals("POST", ourRequestMethod); + assertThat(ourRequestBodyString, containsString("\"resourceType\":\"Parameters\",\n")); + assertNotNull(response.getOperationOutcome()); + assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssue().get(0).getDiagnosticsElement().getValue()); + + } + + @Test + public void testValidateNonFluent() throws Exception { + OperationOutcome oo = new OperationOutcome(); + oo.addIssue().setDiagnostics("FOOBAR"); + final String msg = ourCtx.newXmlParser().encodeResourceToString(oo); + + ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8"; + ourResponseBody = msg; + + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir"); + + Patient p = new Patient(); + p.addName().addGiven("GIVEN"); + + + MethodOutcome response; + + //@formatter:off + response = client.validate(p); + //@formatter:on + + assertEquals("http://localhost:" + ourPort + "/fhir/Patient/$validate", ourRequestUri); + assertEquals("POST", ourRequestMethod); + assertEquals("", ourRequestBodyString); + assertNotNull(response.getResource()); + assertEquals("FOOBAR", toOo(response.getResource()).getIssue().get(0).getDiagnosticsElement().getValue()); + + } + + private OperationOutcome toOo(IBaseResource theOperationOutcome) { + return (OperationOutcome) theOperationOutcome; + } + + @Before + public void beforeReset() { + ourRequestUri = null; + ourRequestUriAll = Lists.newArrayList(); + ourResponseStatus = 200; + ourResponseBody = null; + ourResponseBodies = null; + ourResponseCount = 0; + + ourResponseContentType = null; + ourRequestContentType = null; + ourRequestBodyBytes = null; + ourRequestBodyString = null; + ourRequestHeaders = null; + ourRequestFirstHeaders = null; + ourRequestMethod = null; + ourRequestHeadersAll = Lists.newArrayList(); + } + + private static List ourRequestUriAll; + private static String ourRequestMethod; + private static String ourRequestContentType; + private static byte[] ourRequestBodyBytes; + private static String ourRequestBodyString; + private static ArrayListMultimap ourRequestHeaders; + private static List> ourRequestHeadersAll; + private static Map ourRequestFirstHeaders; + + @BeforeClass + public static void beforeClass() throws Exception { + ourCtx = FhirContext.forDstu3(); + + ourPort = RandomServerPortProvider.findFreePort(); + ourServer = new Server(ourPort); + ourLog.info("Starting server on port {}", ourPort); + ourServer.setHandler(new AbstractHandler() { + + @Override + public void handle(String theArg0, Request theRequest, HttpServletRequest theServletRequest, HttpServletResponse theResp) throws IOException, ServletException { + theRequest.setHandled(true); + ourRequestUri = "http:" + theRequest.getHttpURI().toString(); + ourRequestUriAll.add(ourRequestUri); + ourRequestMethod = theRequest.getMethod(); + ourRequestContentType = theServletRequest.getContentType(); + ourRequestBodyBytes = IOUtils.toByteArray(theServletRequest.getInputStream()); + ourRequestBodyString = new String(ourRequestBodyBytes, Charsets.UTF_8); + + ourRequestHeaders = ArrayListMultimap.create(); + ourRequestHeadersAll.add(ourRequestHeaders); + ourRequestFirstHeaders = Maps.newHashMap(); + + for (Enumeration headerNameEnum = theRequest.getHeaderNames(); headerNameEnum.hasMoreElements(); ) { + String nextName = headerNameEnum.nextElement(); + for (Enumeration headerValueEnum = theRequest.getHeaders(nextName); headerValueEnum.hasMoreElements(); ) { + String nextValue = headerValueEnum.nextElement(); + if (ourRequestFirstHeaders.containsKey(nextName)==false) { + ourRequestFirstHeaders.put(nextName, new Header(nextName, nextValue)); + } + ourRequestHeaders.put(nextName, new Header(nextName, nextValue)); + } + } + + theResp.setStatus(ourResponseStatus); + + if (ourResponseBody != null) { + theResp.setContentType(ourResponseContentType); + theResp.getWriter().write(ourResponseBody); + } else if (ourResponseBodies != null) { + theResp.setContentType(ourResponseContentType); + theResp.getWriter().write(ourResponseBodies[ourResponseCount]); + } + + ourResponseCount++; + } + }); + + ourServer.start(); + } + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } +} diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderDstu3Test.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderDstu3Test.java new file mode 100644 index 00000000000..c12f12b0b4d --- /dev/null +++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderDstu3Test.java @@ -0,0 +1,110 @@ +package ca.uhn.fhir.jaxrs.server; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.net.URI; +import java.util.Arrays; +import java.util.concurrent.ConcurrentHashMap; + +import javax.ws.rs.HttpMethod; +import javax.ws.rs.core.MultivaluedHashMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.glassfish.jersey.internal.MapPropertiesDelegate; +import org.glassfish.jersey.server.ContainerRequest; +import org.junit.Before; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.jaxrs.server.test.TestJaxRsDummyPatientProvider; +import ca.uhn.fhir.jaxrs.server.test.TestJaxRsMockPatientRestProviderDstu3; +import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.IResourceProvider; + +public class AbstractJaxRsConformanceProviderDstu3Test { + + private static final String BASEURI = "http://basiuri"; + private static final String REQUESTURI = BASEURI + "/metadata"; + AbstractJaxRsConformanceProvider provider; + private ConcurrentHashMap, IResourceProvider> providers; + private ContainerRequest headers; + private MultivaluedHashMap queryParameters; + + @Before + public void setUp() throws Exception { + // headers + headers = new ContainerRequest(new URI(BASEURI), new URI(REQUESTURI), HttpMethod.GET, null, + new MapPropertiesDelegate()); + // uri info + queryParameters = new MultivaluedHashMap(); + + + providers = new ConcurrentHashMap, IResourceProvider>(); + provider = createConformanceProvider(providers); + } + + @Test + public void testConformance() throws Exception { + providers.put(AbstractJaxRsConformanceProvider.class, provider); + providers.put(TestJaxRsDummyPatientProvider.class, new TestJaxRsDummyPatientProvider()); + Response response = createConformanceProvider(providers).conformance(); + System.out.println(response); + } + + @Test + public void testConformanceUsingOptions() throws Exception { + providers.put(AbstractJaxRsConformanceProvider.class, provider); + providers.put(TestJaxRsDummyPatientProvider.class, new TestJaxRsDummyPatientProvider()); + Response response = createConformanceProvider(providers).conformanceUsingOptions(); + System.out.println(response); + } + + @Test + public void testConformanceWithMethods() throws Exception { + providers.put(AbstractJaxRsConformanceProvider.class, provider); + providers.put(TestJaxRsMockPatientRestProviderDstu3.class, new TestJaxRsMockPatientRestProviderDstu3()); + Response response = createConformanceProvider(providers).conformance(); + assertEquals(Constants.STATUS_HTTP_200_OK, response.getStatus()); + assertTrue(response.getEntity().toString().contains("\"type\":\"Patient\"")); + assertTrue(response.getEntity().toString().contains("\"$someCustomOperation")); + System.out.println(response); + System.out.println(response.getEntity()); + } + + @Test + public void testConformanceInXml() throws Exception { + queryParameters.put(Constants.PARAM_FORMAT, Arrays.asList(Constants.CT_XML)); + providers.put(AbstractJaxRsConformanceProvider.class, provider); + providers.put(TestJaxRsMockPatientRestProviderDstu3.class, new TestJaxRsMockPatientRestProviderDstu3()); + Response response = createConformanceProvider(providers).conformance(); + assertEquals(Constants.STATUS_HTTP_200_OK, response.getStatus()); + System.out.println(response.getEntity()); + assertTrue(response.getEntity().toString().contains(" ")); + assertTrue(response.getEntity().toString().contains("\"$someCustomOperation")); + System.out.println(response.getEntity()); + } + + private AbstractJaxRsConformanceProvider createConformanceProvider(final ConcurrentHashMap, IResourceProvider> providers) + throws Exception { + AbstractJaxRsConformanceProvider result = new AbstractJaxRsConformanceProvider(FhirContext.forDstu3(), null, null, null) { + @Override + protected ConcurrentHashMap, IResourceProvider> getProviders() { + return providers; + } + }; + // mocks + UriInfo uriInfo = mock(UriInfo.class); + when(uriInfo.getQueryParameters()).thenReturn(queryParameters); + when(uriInfo.getBaseUri()).thenReturn(new URI(BASEURI)); + when(uriInfo.getRequestUri()).thenReturn(new URI(BASEURI + "/foo")); + result.setUriInfo(uriInfo); + result.setHeaders(headers); + result.setUpPostConstruct(); + return result; + } + +} diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProviderDstu3Test.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProviderDstu3Test.java new file mode 100644 index 00000000000..5eeb72ad589 --- /dev/null +++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProviderDstu3Test.java @@ -0,0 +1,443 @@ +package ca.uhn.fhir.jaxrs.server; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.argThat; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.isNull; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.hl7.fhir.dstu3.model.Bundle; +import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent; +import org.hl7.fhir.dstu3.model.Conformance; +import org.hl7.fhir.dstu3.model.DateType; +import org.hl7.fhir.dstu3.model.IdType; +import org.hl7.fhir.dstu3.model.Identifier; +import org.hl7.fhir.dstu3.model.Parameters; +import org.hl7.fhir.dstu3.model.Patient; +import org.hl7.fhir.dstu3.model.Resource; +import org.hl7.fhir.dstu3.model.StringType; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runners.MethodSorters; +import org.mockito.ArgumentCaptor; +import org.mockito.ArgumentMatcher; +import org.mockito.Matchers; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.jaxrs.client.JaxRsRestfulClientFactory; +import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor; +import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsResponseException; +import ca.uhn.fhir.jaxrs.server.test.RandomServerPortProvider; +import ca.uhn.fhir.jaxrs.server.test.TestJaxRsConformanceRestProviderDstu3; +import ca.uhn.fhir.jaxrs.server.test.TestJaxRsMockPageProviderDstu3; +import ca.uhn.fhir.jaxrs.server.test.TestJaxRsMockPatientRestProviderDstu3; +import ca.uhn.fhir.model.base.resource.BaseOperationOutcome; +import ca.uhn.fhir.model.primitive.UriDt; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.api.PreferReturnEnum; +import ca.uhn.fhir.rest.client.IGenericClient; +import ca.uhn.fhir.rest.client.ServerValidationModeEnum; +import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; +import ca.uhn.fhir.rest.method.SearchStyleEnum; +import ca.uhn.fhir.rest.param.StringAndListParam; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.server.EncodingEnum; +import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class AbstractJaxRsResourceProviderDstu3Test { + + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(AbstractJaxRsResourceProviderDstu3Test.class); + private static IGenericClient client; + + + private static final FhirContext ourCtx = FhirContext.forDstu3(); + private static final String PATIENT_NAME = "Van Houte"; + + private static int ourPort; + private static String serverBase; + private static Server jettyServer; + private TestJaxRsMockPatientRestProviderDstu3 mock; + private ArgumentCaptor idCaptor; + private ArgumentCaptor patientCaptor; + + private void compareResultId(int id, IBaseResource resource) { + assertEquals(id, Integer.parseInt(resource.getIdElement().getIdPart())); + } + + private void compareResultUrl(String url, IBaseResource resource) { + assertEquals(url, resource.getIdElement().getValueAsString().substring(serverBase.length() - 1)); + } + + private Patient createPatient(long id) { + Patient theResource = new Patient(); + theResource.setId(new IdType(id)); + return theResource; + } + + private List createPatients(int firstId, int lastId) { + List result = new ArrayList(lastId - firstId); + for (long i = firstId; i <= lastId; i++) { + result.add(createPatient(i)); + } + return result; + } + + /** Find By Id */ + @Test + public void findUsingGenericClientById() { + when(mock.find(any(IdType.class))).thenReturn(createPatient(1)); + Patient result = client.read(Patient.class, "1"); + compareResultId(1, result); + compareResultUrl("/Patient/1", result); + reset(mock); + when(mock.find(eq(result.getIdElement()))).thenReturn(createPatient(1)); + result = (Patient) client.read(new UriDt(result.getId())); + compareResultId(1, result); + compareResultUrl("/Patient/1", result); + } + + private Bundle getPatientBundle(int size) { + Bundle result = new Bundle(); + for (long i = 0; i < size; i++) { + Patient patient = createPatient(i); + BundleEntryComponent entry = new BundleEntryComponent(); + entry.setResource(patient); + result.addEntry(entry); + } + return result; + } + + @Before + public void setUp() { + this.mock = TestJaxRsMockPatientRestProviderDstu3.mock; + idCaptor = ArgumentCaptor.forClass(IdType.class); + patientCaptor = ArgumentCaptor.forClass(Patient.class); + reset(mock); + } + + /** Conditional Creates */ + @Test + public void testConditionalCreate() throws Exception { + Patient toCreate = createPatient(1); + MethodOutcome outcome = new MethodOutcome(); + toCreate.getIdentifier().add(new Identifier().setValue("myIdentifier")); + outcome.setResource(toCreate); + + when(mock.create(patientCaptor.capture(), eq("Patient?_format=json&identifier=2"))).thenReturn(outcome); + client.setEncoding(EncodingEnum.JSON); + + MethodOutcome response = client.create().resource(toCreate).conditional() + .where(Patient.IDENTIFIER.exactly().identifier("2")).prefer(PreferReturnEnum.REPRESENTATION).execute(); + + assertEquals("myIdentifier", patientCaptor.getValue().getIdentifier().get(0).getValue()); + IBaseResource resource = response.getResource(); + compareResultId(1, resource); + } + + /** Conformance - Server */ + @Test + public void testConformance() { + final Conformance conf = client.fetchConformance().ofType(Conformance.class).execute(); + assertEquals(conf.getRest().get(0).getResource().get(0).getType().toString(), "Patient"); + } + + @Test + public void testCreatePatient() throws Exception { + Patient toCreate = createPatient(1); + MethodOutcome outcome = new MethodOutcome(); + toCreate.getIdentifier().add(new Identifier().setValue("myIdentifier")); + outcome.setResource(toCreate); + + when(mock.create(patientCaptor.capture(), isNull(String.class))).thenReturn(outcome); + client.setEncoding(EncodingEnum.JSON); + final MethodOutcome response = client.create().resource(toCreate).prefer(PreferReturnEnum.REPRESENTATION) + .execute(); + IBaseResource resource = (IBaseResource) response.getResource(); + compareResultId(1, resource); + assertEquals("myIdentifier", patientCaptor.getValue().getIdentifier().get(0).getValue()); + } + + @Test + public void testDeletePatient() { + when(mock.delete(idCaptor.capture())).thenReturn(new MethodOutcome()); + final BaseOperationOutcome results = client.delete().resourceById("Patient", "1").execute(); + assertEquals("1", idCaptor.getValue().getIdPart()); + } + + /** Extended Operations */ + @Test + public void testExtendedOperations() { + // prepare mock + Parameters resultParameters = new Parameters(); + resultParameters.addParameter().setName("return").setResource(createPatient(1)).setValue(new StringType("outputValue")); + when(mock.someCustomOperation(any(IdType.class), argThat(new StringTypeMatcher(new StringType("myAwesomeDummyValue"))))).thenReturn(resultParameters); + // Create the input parameters to pass to the server + Parameters inParams = new Parameters(); + inParams.addParameter().setName("start").setValue(new DateType("2001-01-01")); + inParams.addParameter().setName("end").setValue(new DateType("2015-03-01")); + inParams.addParameter().setName("dummy").setValue(new StringType("myAwesomeDummyValue")); + //invoke + Parameters outParams = client.operation().onInstance(new IdType("Patient", "1")).named("$someCustomOperation") + .withParameters(inParams).execute(); + //verify + assertEquals("outputValue", ((StringType)outParams.getParameter().get(0).getValue()).getValueAsString()); + } + + class StringTypeMatcher extends ArgumentMatcher { + private StringType myStringType; + + public StringTypeMatcher(StringType stringType) { + myStringType = stringType; + } + + @Override + public boolean matches(Object argument) { + return myStringType.getValue().equals(((StringType)argument).getValue()); + } + + } + + @Test + public void testExtendedOperationsUsingGet() { + // prepare mock + Parameters resultParameters = new Parameters(); + resultParameters.addParameter().setName("return").setResource(createPatient(1)).setValue(new StringType("outputValue")); + when(mock.someCustomOperation(any(IdType.class), argThat(new StringTypeMatcher(new StringType("myAwesomeDummyValue"))))).thenReturn(resultParameters); + // Create the input parameters to pass to the server + Parameters inParams = new Parameters(); + inParams.addParameter().setName("start").setValue(new DateType("2001-01-01")); + inParams.addParameter().setName("end").setValue(new DateType("2015-03-01")); + inParams.addParameter().setName("dummy").setValue(new StringType("myAwesomeDummyValue")); + + // invoke + Parameters outParams = client.operation().onInstance(new IdType("Patient", "1")).named("$someCustomOperation") + .withParameters(inParams).useHttpGet().execute(); + // verify + assertEquals("outputValue", ((StringType)outParams.getParameter().get(0).getValue()).getValueAsString()); + } + + /** Search using other query options */ + public void testOther() { + // missing + } + + @Test + public void testRead() { + when(mock.find(idCaptor.capture())).thenReturn(createPatient(1)); + final Patient patient = client.read(Patient.class, "1"); + compareResultId(1, patient); + compareResultUrl("/Patient/1", patient); + assertEquals("1", idCaptor.getValue().getIdPart()); + } + + /** Search - Compartments */ + @Test + public void testSearchCompartements() { + when(mock.searchCompartment(any(IdType.class))).thenReturn(Arrays.asList((IBaseResource) createPatient(1))); + org.hl7.fhir.dstu3.model.Bundle response = client.search().forResource(Patient.class).withIdAndCompartment("1", "Condition") + .returnBundle(org.hl7.fhir.dstu3.model.Bundle.class).execute(); + Resource resource = response.getEntry().get(0).getResource(); + compareResultId(1, resource); + compareResultUrl("/Patient/1", resource); + } + + /** */ + @Test + public void testSearchPost() { + when(mock.search(any(StringParam.class), Matchers.isNull(StringAndListParam.class))) + .thenReturn(createPatients(1, 13)); + org.hl7.fhir.dstu3.model.Bundle result = client.search().forResource("Patient").usingStyle(SearchStyleEnum.POST) + .returnBundle(org.hl7.fhir.dstu3.model.Bundle.class).execute(); + Resource resource = result.getEntry().get(0).getResource(); + compareResultId(1, resource); + compareResultUrl("/Patient/1", resource); + } + + /** Search/Query - Type */ + @Test + public void testSearchUsingGenericClientBySearch() { + // Perform a search + when(mock.search(any(StringParam.class), Matchers.isNull(StringAndListParam.class))) + .thenReturn(Arrays.asList(createPatient(1))); + final Bundle results = client.search().forResource(Patient.class) + .where(Patient.NAME.matchesExactly().value(PATIENT_NAME)).returnBundle(Bundle.class).execute(); + verify(mock).search(any(StringParam.class), Matchers.isNull(StringAndListParam.class)); + IBaseResource resource = results.getEntry().get(0).getResource(); + + compareResultId(1, resource); + compareResultUrl("/Patient/1", resource); + } + + /** Search - Multi-valued Parameters (ANY/OR) */ + @Test + public void testSearchUsingGenericClientBySearchWithMultiValues() { + when(mock.search(any(StringParam.class), Matchers.isNotNull(StringAndListParam.class))) + .thenReturn(Arrays.asList(createPatient(1))); + final Bundle results = client.search().forResource(Patient.class) + .where(Patient.ADDRESS.matches().values("Toronto")).and(Patient.ADDRESS.matches().values("Ontario")) + .and(Patient.ADDRESS.matches().values("Canada")) + .where(Patient.IDENTIFIER.exactly().systemAndIdentifier("SHORTNAME", "TOYS")).returnBundle(Bundle.class).execute(); + IBaseResource resource = results.getEntry().get(0).getResource(); + + compareResultId(1, resource); + compareResultUrl("/Patient/1", resource); + } + + /** Search - Paging */ + @Test + public void testSearchWithPaging() { + // Perform a search + when(mock.search(any(StringParam.class), Matchers.isNull(StringAndListParam.class))) + .thenReturn(createPatients(1, 13)); + final org.hl7.fhir.dstu3.model.Bundle results = client.search().forResource(Patient.class).count(8).returnBundle(org.hl7.fhir.dstu3.model.Bundle.class) + .execute(); + + assertEquals(results.getEntry().size(), 8); + IBaseResource resource = results.getEntry().get(0).getResource(); + compareResultId(1, resource); + compareResultUrl("/Patient/1", resource); + compareResultId(8, results.getEntry().get(7).getResource()); + +// ourLog.info("Next: " + results.getLink("next").getUrl()); +// String url = results.getLink("next").getUrl().replace("?", "Patient?"); +// results.getLink("next").setUrl(url); +// ourLog.info("New Next: " + results.getLink("next").getUrl()); + + // load next page + final org.hl7.fhir.dstu3.model.Bundle nextPage = client.loadPage().next(results).execute(); + resource = nextPage.getEntry().get(0).getResource(); + compareResultId(9, resource); + compareResultUrl("/Patient/9", resource); + assertNull(nextPage.getLink(org.hl7.fhir.dstu3.model.Bundle.LINK_NEXT)); + } + + /** Search - Subsetting (_summary and _elements) */ + @Test + @Ignore + public void testSummary() { + Object response = client.search().forResource(Patient.class) + .returnBundle(org.hl7.fhir.dstu3.model.Bundle.class).execute(); + } + + /** Transaction - Server */ +// @Ignore +// @Test +// public void testTransaction() { +// ca.uhn.fhir.model.api.Bundle bundle = new ca.uhn.fhir.model.api.Bundle(); +// BundleEntry entry = bundle.addEntry(); +// final Patient existing = new Patient(); +// existing.getName().get(0).addFamily("Created with bundle"); +// entry.setResource(existing); +// +// BoundCodeDt theTransactionOperation = new BoundCodeDt( +// BundleEntryTransactionMethodEnum.VALUESET_BINDER, BundleEntryTransactionMethodEnum.POST); +// entry.setTransactionMethod(theTransactionOperation); +// ca.uhn.fhir.model.api.Bundle response = client.transaction().withBundle(bundle).execute(); +// } + + @Test + public void testUpdateById() throws Exception { + when(mock.update(idCaptor.capture(), patientCaptor.capture())).thenReturn(new MethodOutcome()); + client.update("1", createPatient(1)); + assertEquals("1", idCaptor.getValue().getIdPart()); + compareResultId(1, patientCaptor.getValue()); + } + + @SuppressWarnings("unchecked") + @Ignore + @Test + public void testResourceNotFound() throws Exception { + when(mock.update(idCaptor.capture(), patientCaptor.capture())).thenThrow(ResourceNotFoundException.class); + try { + client.update("1", createPatient(2)); + fail(); + } catch (ResourceNotFoundException e) { + // good + } + } + + @Test + public void testVRead() { + when(mock.findHistory(idCaptor.capture())).thenReturn(createPatient(1)); + final Patient patient = client.vread(Patient.class, "1", "2"); + compareResultId(1, patient); + compareResultUrl("/Patient/1", patient); + assertEquals("1", idCaptor.getValue().getIdPart()); + assertEquals("2", idCaptor.getValue().getVersionIdPart()); + } + + @Test + public void testXFindUnknownPatient() { + try { + JaxRsResponseException notFoundException = new JaxRsResponseException(new ResourceNotFoundException(new IdType("999955541264"))); + when(mock.find(idCaptor.capture())).thenThrow(notFoundException); + client.read(Patient.class, "999955541264"); + fail(); + } catch (final ResourceNotFoundException e) { + assertEquals(ResourceNotFoundException.STATUS_CODE, e.getStatusCode()); + assertTrue(e.getMessage().contains("999955541264")); + } + } + + @BeforeClass + public static void setUpClass() throws Exception { + ourPort = RandomServerPortProvider.findFreePort(); + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/"); + System.out.println(ourPort); + jettyServer = new Server(ourPort); + jettyServer.setHandler(context); + ServletHolder jerseyServlet = context.addServlet(org.glassfish.jersey.servlet.ServletContainer.class, "/*"); + jerseyServlet.setInitOrder(0); + + //@formatter:off + jerseyServlet.setInitParameter("jersey.config.server.provider.classnames", + StringUtils.join(Arrays.asList( + TestJaxRsMockPatientRestProviderDstu3.class.getCanonicalName(), + JaxRsExceptionInterceptor.class.getCanonicalName(), + TestJaxRsConformanceRestProviderDstu3.class.getCanonicalName(), + TestJaxRsMockPageProviderDstu3.class.getCanonicalName() + ), ";")); + //@formatter:on + + jettyServer.start(); + + ourCtx.setRestfulClientFactory(new JaxRsRestfulClientFactory(ourCtx)); + ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); + ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); + serverBase = "http://localhost:" + ourPort + "/"; + client = ourCtx.newRestfulGenericClient(serverBase); + client.setEncoding(EncodingEnum.JSON); + client.registerInterceptor(new LoggingInterceptor(true)); + } + + @AfterClass + public static void tearDownClass() throws Exception { + try { + jettyServer.destroy(); + } catch (Exception e) { + + } + } + +} diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsConformanceRestProviderDstu3.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsConformanceRestProviderDstu3.java new file mode 100644 index 00000000000..1cbaff2a585 --- /dev/null +++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsConformanceRestProviderDstu3.java @@ -0,0 +1,34 @@ +package ca.uhn.fhir.jaxrs.server.test; + +import java.util.concurrent.ConcurrentHashMap; + +import javax.ejb.Stateless; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.jaxrs.server.AbstractJaxRsConformanceProvider; +import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.IResourceProvider; + +/** + * A conformance provider exposes the mock patient and this provider + */ +@Path("") +@Stateless +@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML }) +public class TestJaxRsConformanceRestProviderDstu3 extends AbstractJaxRsConformanceProvider { + + public TestJaxRsConformanceRestProviderDstu3() { + super(FhirContext.forDstu3(), "description", "name", "version"); + } + + @Override + protected ConcurrentHashMap, IResourceProvider> getProviders() { + ConcurrentHashMap, IResourceProvider> map = new ConcurrentHashMap, IResourceProvider>(); + map.put(TestJaxRsMockPatientRestProviderDstu3.class, new TestJaxRsMockPatientRestProviderDstu3()); + map.put(TestJaxRsConformanceRestProviderDstu3.class, new TestJaxRsConformanceRestProviderDstu3()); + return map; + } +} diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsDummyPatientProviderDstu3.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsDummyPatientProviderDstu3.java new file mode 100644 index 00000000000..32fa1bc439e --- /dev/null +++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsDummyPatientProviderDstu3.java @@ -0,0 +1,21 @@ +package ca.uhn.fhir.jaxrs.server.test; + +import org.hl7.fhir.dstu3.model.Patient; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider; + +/** + * A dummy patient provider exposing no methods + */ +public class TestJaxRsDummyPatientProviderDstu3 extends AbstractJaxRsResourceProvider { + + public TestJaxRsDummyPatientProviderDstu3() { + super(FhirContext.forDstu3()); + } + + @Override + public Class getResourceType() { + return Patient.class; + } +} diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPageProviderDstu3.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPageProviderDstu3.java new file mode 100644 index 00000000000..e6351fb47e0 --- /dev/null +++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPageProviderDstu3.java @@ -0,0 +1,26 @@ +package ca.uhn.fhir.jaxrs.server.test; + +import javax.ejb.Stateless; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.jaxrs.server.AbstractJaxRsPageProvider; +import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.IPagingProvider; + +@Path("/") +@Stateless +@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML }) +public class TestJaxRsMockPageProviderDstu3 extends AbstractJaxRsPageProvider { + + public TestJaxRsMockPageProviderDstu3() { + super(FhirContext.forDstu3()); + } + @Override + public IPagingProvider getPagingProvider() { + return TestJaxRsMockPatientRestProviderDstu3.PAGING_PROVIDER; + } + +} diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProviderDstu3.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProviderDstu3.java new file mode 100644 index 00000000000..1cf3caed218 --- /dev/null +++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProviderDstu3.java @@ -0,0 +1,141 @@ +package ca.uhn.fhir.jaxrs.server.test; + +import java.util.List; + +import javax.ejb.Stateless; +import javax.interceptor.Interceptors; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.hl7.fhir.dstu3.model.IdType; +import org.hl7.fhir.dstu3.model.Parameters; +import org.hl7.fhir.dstu3.model.Patient; +import org.hl7.fhir.dstu3.model.StringType; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.mockito.Mockito; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider; +import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.rest.annotation.ConditionalUrlParam; +import ca.uhn.fhir.rest.annotation.Create; +import ca.uhn.fhir.rest.annotation.Delete; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Operation; +import ca.uhn.fhir.rest.annotation.OperationParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.ResourceParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.annotation.Update; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.api.RequestTypeEnum; +import ca.uhn.fhir.rest.api.RestOperationTypeEnum; +import ca.uhn.fhir.rest.param.StringAndListParam; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider; +import ca.uhn.fhir.rest.server.IPagingProvider; + +/** + * A test server delegating each call to a mock + */ +@Path(TestJaxRsMockPatientRestProviderDstu3.PATH) +@Stateless +@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML }) +@Interceptors(JaxRsExceptionInterceptor.class) +public class TestJaxRsMockPatientRestProviderDstu3 extends AbstractJaxRsResourceProvider { + + static final String PATH = "/Patient"; + + public static final TestJaxRsMockPatientRestProviderDstu3 mock = Mockito.mock(TestJaxRsMockPatientRestProviderDstu3.class); + + public static final FifoMemoryPagingProvider PAGING_PROVIDER; + + static + { + PAGING_PROVIDER = new FifoMemoryPagingProvider(10); + PAGING_PROVIDER.setDefaultPageSize(10); + PAGING_PROVIDER.setMaximumPageSize(100); + } + + /** + * Constructor + */ + public TestJaxRsMockPatientRestProviderDstu3() { + super(FhirContext.forDstu3()); + } + + @Search + public List search(@RequiredParam(name = Patient.SP_NAME) final StringParam name, @RequiredParam(name=Patient.SP_ADDRESS) StringAndListParam theAddressParts) { + return mock.search(name, theAddressParts); + } + + @Update + public MethodOutcome update(@IdParam final IdType theId, @ResourceParam final Patient patient) throws Exception { + return mock.update(theId, patient); + } + + @Read + public Patient find(@IdParam final IdType theId) { + return mock.find(theId); + } + + @Read(version = true) + public Patient findHistory(@IdParam final IdType theId) { + return mock.findHistory(theId); + } + + @Create + public MethodOutcome create(@ResourceParam final Patient patient, @ConditionalUrlParam String theConditional) + throws Exception { + return mock.create(patient, theConditional); + } + + @Delete + public MethodOutcome delete(@IdParam final IdType theId) { + return mock.delete(theId); + } + + @Search(compartmentName = "Condition") + public List searchCompartment(@IdParam IdType thePatientId) { + return mock.searchCompartment(thePatientId); + } + + @GET + @Path("/{id}/$someCustomOperation") + public Response someCustomOperationUsingGet(@PathParam("id") String id, String resource) throws Exception { + return customOperation(resource, RequestTypeEnum.GET, id, "$someCustomOperation", + RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE); + } + + @POST + @Path("/{id}/$someCustomOperation") + public Response someCustomOperationUsingPost(@PathParam("id") String id, String resource) throws Exception { + return customOperation(resource, RequestTypeEnum.POST, id, "$someCustomOperation", + RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE); + } + + @Operation(name = "someCustomOperation", idempotent = true, returnParameters = { + @OperationParam(name = "return", type = StringType.class) }) + public Parameters someCustomOperation(@IdParam IdType myId, @OperationParam(name = "dummy") StringType dummyInput) { + return mock.someCustomOperation(myId, dummyInput); + } + + @Override + public Class getResourceType() { + return Patient.class; + } + + @Override + public IPagingProvider getPagingProvider() { + return PAGING_PROVIDER; + } + +} diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/util/JaxRsMethodBindingsDstu3Test.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/util/JaxRsMethodBindingsDstu3Test.java new file mode 100644 index 00000000000..744b1f32fb7 --- /dev/null +++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/util/JaxRsMethodBindingsDstu3Test.java @@ -0,0 +1,129 @@ +package ca.uhn.fhir.jaxrs.server.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.List; + +import org.hl7.fhir.dstu3.model.IdType; +import org.hl7.fhir.dstu3.model.Parameters; +import org.hl7.fhir.dstu3.model.Patient; +import org.hl7.fhir.dstu3.model.StringType; +import org.junit.Before; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import ca.uhn.fhir.jaxrs.server.test.TestJaxRsDummyPatientProviderDstu3; +import ca.uhn.fhir.jaxrs.server.util.JaxRsMethodBindings; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Operation; +import ca.uhn.fhir.rest.annotation.OperationParam; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.ResourceParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.annotation.Update; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.api.RestOperationTypeEnum; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.server.exceptions.NotImplementedOperationException; + +@FixMethodOrder(MethodSorters.DEFAULT) +public class JaxRsMethodBindingsDstu3Test { + + @Before + public void setUp() { + JaxRsMethodBindings.getClassBindings().clear(); + } + + @Test(expected = NotImplementedOperationException.class) + public void testFindMethodsForProviderNotDefinedMappingMethods() { + new TestJaxRsDummyPatientProviderDstu3().getBindings().getBinding(RestOperationTypeEnum.UPDATE, ""); + } + + @Test + public void testFindMethodsForProviderWithMethods() { + class TestFindPatientProvider extends TestJaxRsDummyPatientProviderDstu3 { + @Search + public List search(@RequiredParam(name = Patient.SP_NAME) final StringParam name) { + return null; + } + } + new TestFindPatientProvider(); + assertEquals(TestFindPatientProvider.class, new TestFindPatientProvider().getBindings().getBinding(RestOperationTypeEnum.SEARCH_TYPE, "").getMethod().getDeclaringClass()); + } + + @Test + public void testFindMethodsFor2ProvidersWithMethods() { + class TestFindPatientProvider extends TestJaxRsDummyPatientProviderDstu3 { + @Search + public List search(@RequiredParam(name = Patient.SP_NAME) final StringParam name) { + return null; + } + } + class TestUpdatePatientProvider extends TestJaxRsDummyPatientProviderDstu3 { + @Update + public MethodOutcome update(@IdParam final IdType theId, @ResourceParam final Patient patient) { + return null; + } + } + assertEquals(TestFindPatientProvider.class, new TestFindPatientProvider().getBindings().getBinding(RestOperationTypeEnum.SEARCH_TYPE, "").getMethod().getDeclaringClass()); + assertEquals(TestUpdatePatientProvider.class, new TestUpdatePatientProvider().getBindings().getBinding(RestOperationTypeEnum.UPDATE, "").getMethod().getDeclaringClass()); + } + + @Test + public void testFindMethodsWithDoubleMethodsDeclaration() { + class TestDoubleSearchProvider extends TestJaxRsDummyPatientProviderDstu3 { + @Search + public List search1(@RequiredParam(name = Patient.SP_NAME) final StringParam name) { + return null; + } + + @Search + public List search2(@RequiredParam(name = Patient.SP_NAME) final StringParam name) { + return null; + } + } + try { + new TestDoubleSearchProvider(); + fail(); + } catch(IllegalArgumentException e) { + assertTrue(e.getMessage().contains("search1")); + assertTrue(e.getMessage().contains("search2")); + } + } + + @Test + public void testFindMethodsWithMultipleMethods() { + class TestFindPatientProvider extends TestJaxRsDummyPatientProviderDstu3 { + @Search + public List search(@RequiredParam(name = Patient.SP_NAME) final StringParam name) { + return null; + } + @Update + public MethodOutcome update(@IdParam final IdType theId, @ResourceParam final Patient patient) { + return null; + } + @Operation(name = "firstMethod", idempotent = true, returnParameters = { @OperationParam(name = "return", type = StringType.class) }) + public Parameters firstMethod(@OperationParam(name = "dummy") StringType dummyInput) { + return null; + } + @Operation(name = "secondMethod", returnParameters = { @OperationParam(name = "return", type = StringType.class) }) + public Parameters secondMethod(@OperationParam(name = "dummy") StringType dummyInput) { + return null; + } + } + JaxRsMethodBindings bindings = new TestFindPatientProvider().getBindings(); + assertEquals("search", bindings.getBinding(RestOperationTypeEnum.SEARCH_TYPE, "").getMethod().getName()); + assertEquals("update", bindings.getBinding(RestOperationTypeEnum.UPDATE, "").getMethod().getName()); + assertEquals("firstMethod", bindings.getBinding(RestOperationTypeEnum.EXTENDED_OPERATION_TYPE, "$firstMethod").getMethod().getName()); + assertEquals("secondMethod", bindings.getBinding(RestOperationTypeEnum.EXTENDED_OPERATION_TYPE, "$secondMethod").getMethod().getName()); + try { + bindings.getBinding(RestOperationTypeEnum.EXTENDED_OPERATION_TYPE, "$thirdMethod"); + fail(); + } catch(NotImplementedOperationException e){ + } + } + +} diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/util/JaxRsRequestDstu3Test.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/util/JaxRsRequestDstu3Test.java new file mode 100644 index 00000000000..87331c24b4d --- /dev/null +++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/util/JaxRsRequestDstu3Test.java @@ -0,0 +1,119 @@ +package ca.uhn.fhir.jaxrs.server.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; + +import javax.ws.rs.HttpMethod; +import javax.ws.rs.core.MultivaluedHashMap; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.UriInfo; + +import org.apache.commons.lang3.StringUtils; +import org.glassfish.jersey.internal.MapPropertiesDelegate; +import org.glassfish.jersey.server.ContainerRequest; +import org.junit.Before; +import org.junit.Test; + +import ca.uhn.fhir.jaxrs.server.test.TestJaxRsDummyPatientProvider; +import ca.uhn.fhir.jaxrs.server.test.TestJaxRsDummyPatientProviderDstu3; +import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest; +import ca.uhn.fhir.jaxrs.server.util.JaxRsResponse; +import ca.uhn.fhir.rest.api.RequestTypeEnum; +import ca.uhn.fhir.rest.api.RestOperationTypeEnum; + +public class JaxRsRequestDstu3Test { + + private static final String RESOURCE_STRING = ""; + private static final String BASEURI = "http://baseuri"; + private static final String REQUESTURI = "http://baseuri/test"; + + private JaxRsRequest details; + private MultivaluedMap queryParameters = new MultivaluedHashMap(); + private ContainerRequest headers; + private TestJaxRsDummyPatientProviderDstu3 provider; + + @Before + public void setUp() throws URISyntaxException { + details = createRequestDetails(); + } + + @Test + public void testGetHeader() { + String headerKey = "key"; + String headerValue = "location_value"; + String headerValue2 = "location_value_2"; + assertTrue(StringUtils.isBlank(details.getHeader(headerKey))); + headers.header(headerKey, headerValue); + assertEquals(headerValue, details.getHeader(headerKey)); + assertEquals(Arrays.asList(headerValue), details.getHeaders(headerKey)); + + headers.header(headerKey, headerValue2); + assertEquals(headerValue, details.getHeader(headerKey)); + assertEquals(Arrays.asList(headerValue, headerValue2), details.getHeaders(headerKey)); + } + + @Test + public void testGetByteStreamRequestContents() { + assertEquals(RESOURCE_STRING, new String(details.getByteStreamRequestContents())); + } + + @Test + public void testServerBaseForRequest() { + assertEquals(BASEURI, new String(details.getServerBaseForRequest())); + } + + @Test + public void testGetResponse() { + JaxRsResponse response = (JaxRsResponse) details.getResponse(); + assertEquals(details, response.getRequestDetails()); + assertTrue(response == details.getResponse()); + } + + @Test(expected = UnsupportedOperationException.class) + public void testGetReader() throws IOException { + details.getReader(); + } + + @Test(expected = UnsupportedOperationException.class) + public void testGetInputStream() { + details.getInputStream(); + } + + @Test + public void testGetServerBaseForRequest() { + assertEquals(JaxRsRequestDstu3Test.BASEURI, details.getFhirServerBase()); + } + + @Test + public void testGetServer() { + assertEquals(this.provider, details.getServer()); + } + + public JaxRsRequest createRequestDetails() throws URISyntaxException { + //headers + headers = new ContainerRequest(new URI(BASEURI), new URI(REQUESTURI), HttpMethod.GET, null, new MapPropertiesDelegate()); + + //uri info + UriInfo uriInfo = mock(UriInfo.class); + when(uriInfo.getQueryParameters()).thenReturn(queryParameters); + + //mocks + provider = spy(TestJaxRsDummyPatientProviderDstu3.class); + doReturn(uriInfo).when(provider).getUriInfo(); + doReturn(BASEURI).when(provider).getBaseForRequest(); + doReturn(BASEURI).when(provider).getBaseForServer(); + doReturn(headers).when(provider).getHeaders(); + + return new JaxRsRequest(provider, RESOURCE_STRING, RequestTypeEnum.GET, RestOperationTypeEnum.HISTORY_TYPE); + } + +} diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/util/JaxRsResponseDstu3Test.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/util/JaxRsResponseDstu3Test.java new file mode 100644 index 00000000000..57646f10d8e --- /dev/null +++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/util/JaxRsResponseDstu3Test.java @@ -0,0 +1,159 @@ +package ca.uhn.fhir.jaxrs.server.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.Collections; +import java.util.Set; + +import javax.ws.rs.core.Response; + +import org.hl7.fhir.dstu3.model.Binary; +import org.hl7.fhir.dstu3.model.Bundle; +import org.hl7.fhir.dstu3.model.IdType; +import org.hl7.fhir.dstu3.model.Patient; +import org.hl7.fhir.instance.model.api.IBaseBinary; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.junit.Before; +import org.junit.Test; + +import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest; +import ca.uhn.fhir.jaxrs.server.util.JaxRsResponse; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.api.SummaryEnum; +import ca.uhn.fhir.rest.method.ParseAction; +import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.RestfulServerUtils; + +public class JaxRsResponseDstu3Test { + + private JaxRsResponse response; + private JaxRsRequest request; + private Bundle bundle; + private Set theSummaryMode; + + @Before + public void setUp() throws URISyntaxException { + request = new JaxRsRequestDstu3Test().createRequestDetails(); + this.response = (JaxRsResponse) request.getResponse(); + bundle = getSinglePatientResource(); + theSummaryMode = Collections.emptySet(); + } + + @Test + public void testGetResponseWriterNoZipNoBrowser() throws IOException { + boolean theRequestIsBrowser = false; + boolean respondGzip = false; + Set theSummaryMode = Collections.emptySet(); + boolean theAddContentLocationHeader = false; + Response result = (Response) RestfulServerUtils.streamResponseAsResource(request.getServer(), bundle, theSummaryMode, 200, theAddContentLocationHeader, respondGzip, request); + assertEquals(200, result.getStatus()); + assertEquals(Constants.CT_FHIR_JSON+Constants.CHARSET_UTF8_CTSUFFIX, result.getHeaderString(Constants.HEADER_CONTENT_TYPE)); + assertTrue(result.getEntity().toString().contains("Patient")); + assertTrue(result.getEntity().toString().contains("15")); + } + + @Test + public void testSendAttachmentResponse() throws IOException { + boolean theRequestIsBrowser = true; + boolean respondGzip = true; + IBaseBinary binary = new Binary(); + String contentType = "foo"; + byte[] content = new byte[] { 1, 2, 3, 4 }; + binary.setContentType(contentType); + binary.setContent(content); + boolean theAddContentLocationHeader = false; + Response result = (Response) RestfulServerUtils.streamResponseAsResource(request.getServer(), binary, theSummaryMode, 200, theAddContentLocationHeader, respondGzip, this.request); + assertEquals(200, result.getStatus()); + assertEquals(contentType, result.getHeaderString(Constants.HEADER_CONTENT_TYPE)); + assertEquals(content, result.getEntity()); + } + + @Test + public void testSendAttachmentResponseNoContent() throws IOException { + boolean theRequestIsBrowser = true; + boolean respondGzip = true; + IBaseBinary binary = new Binary(); + binary.setContent(new byte[]{}); + boolean theAddContentLocationHeader = false; + Response result = (Response) RestfulServerUtils.streamResponseAsResource(request.getServer(), binary, theSummaryMode, 200, theAddContentLocationHeader, respondGzip, this.request); + assertEquals(200, result.getStatus()); + assertEquals(null, result.getHeaderString(Constants.HEADER_CONTENT_TYPE)); + assertEquals(null, result.getEntity()); + } + + @Test + public void testSendAttachmentResponseEmptyContent() throws IOException { + boolean theRequestIsBrowser = true; + boolean respondGzip = true; + IBaseBinary binary = new Binary(); + boolean theAddContentLocationHeader = false; + Response result = (Response) RestfulServerUtils.streamResponseAsResource(request.getServer(), binary, theSummaryMode, 200, theAddContentLocationHeader, respondGzip, this.request); + assertEquals(200, result.getStatus()); + assertEquals(null, result.getHeaderString(Constants.HEADER_CONTENT_TYPE)); + assertEquals(null, result.getEntity()); + } + + + @Test + public void testReturnResponse() throws IOException { + IdType theId = new IdType(15L); + ParseAction outcome = ParseAction.create(createPatient()); + int operationStatus = 200; + boolean allowPrefer = true; + String resourceName = "Patient"; + MethodOutcome methodOutcome = new MethodOutcome(theId); + Response result = response.returnResponse(outcome, operationStatus, allowPrefer, methodOutcome, resourceName); + assertEquals(200, result.getStatus()); + assertEquals(Constants.CT_JSON+Constants.CHARSET_UTF8_CTSUFFIX, result.getHeaderString(Constants.HEADER_CONTENT_TYPE)); + System.out.println(result.getEntity().toString()); + assertTrue(result.getEntity().toString().contains("resourceType\":\"Patient")); + assertTrue(result.getEntity().toString().contains("15")); + + } + + @Test + public void testReturnResponseAsXml() throws IOException { + IdType theId = new IdType(15L); + ParseAction outcome = ParseAction.create(createPatient()); + int operationStatus = 200; + boolean allowPrefer = true; + String resourceName = "Patient"; + MethodOutcome methodOutcome = new MethodOutcome(theId); + response.getRequestDetails().getParameters().put(Constants.PARAM_FORMAT, new String[]{Constants.CT_XML}); + Response result = response.returnResponse(outcome, operationStatus, allowPrefer, methodOutcome, resourceName); + assertEquals(200, result.getStatus()); + assertEquals(Constants.CT_XML+Constants.CHARSET_UTF8_CTSUFFIX, result.getHeaderString(Constants.HEADER_CONTENT_TYPE)); + assertTrue(result.getEntity().toString().contains(" outcome = ParseAction.create((IBaseResource) null); + int operationStatus = Constants.STATUS_HTTP_204_NO_CONTENT; + boolean allowPrefer = true; + String resourceName = "Patient"; + MethodOutcome methodOutcome = new MethodOutcome(null); + response.getRequestDetails().getParameters().put(Constants.PARAM_FORMAT, new String[]{Constants.CT_XML}); + Response result = response.returnResponse(outcome, operationStatus, allowPrefer, methodOutcome, resourceName); + assertEquals(204, result.getStatus()); + assertEquals(Constants.CT_XML+Constants.CHARSET_UTF8_CTSUFFIX, result.getHeaderString(Constants.HEADER_CONTENT_TYPE)); + } + + private Bundle getSinglePatientResource() { + Patient theResource = createPatient(); + Bundle bundle = new Bundle(); + bundle.addEntry().setResource(theResource); + return bundle; + } + + private Patient createPatient() { + Patient theResource = new Patient(); + theResource.setId(new IdType(15L)); + return theResource; + } + +} diff --git a/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsConformanceProviderDstu3.java b/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsConformanceProviderDstu3.java new file mode 100644 index 00000000000..1ec716d0395 --- /dev/null +++ b/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsConformanceProviderDstu3.java @@ -0,0 +1,46 @@ +package ca.uhn.fhir.jaxrs.server.example; + +import java.util.concurrent.ConcurrentHashMap; + +import javax.ejb.Stateless; +import javax.inject.Inject; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.jaxrs.server.AbstractJaxRsConformanceProvider; +import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.IResourceProvider; + +/** + * Conformance Rest Service + * + * @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare + */ +@Path("") +@Stateless +@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML }) +public class JaxRsConformanceProviderDstu3 extends AbstractJaxRsConformanceProvider { + private static final String SERVER_VERSION = "1.0.0"; + private static final String SERVER_DESCRIPTION = "Jax-Rs Test Example Description"; + private static final String SERVER_NAME = "Jax-Rs Test Example"; + + @Inject + private JaxRsPatientRestProvider patientProvider; + + /** + * Standard Constructor + */ + public JaxRsConformanceProviderDstu3() { + super(FhirContext.forDstu3(), SERVER_VERSION, SERVER_DESCRIPTION, SERVER_NAME); + } + + @Override + protected ConcurrentHashMap, IResourceProvider> getProviders() { + ConcurrentHashMap, IResourceProvider> map = new ConcurrentHashMap, IResourceProvider>(); + map.put(JaxRsConformanceProviderDstu3.class, this); + map.put(JaxRsPatientRestProvider.class, patientProvider); + return map; + } +} diff --git a/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPageProviderDstu3.java b/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPageProviderDstu3.java new file mode 100644 index 00000000000..b3e795dcdd1 --- /dev/null +++ b/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPageProviderDstu3.java @@ -0,0 +1,27 @@ +package ca.uhn.fhir.jaxrs.server.example; + +import javax.ejb.Stateless; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.jaxrs.server.AbstractJaxRsPageProvider; +import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.IPagingProvider; + +@Path("/") +@Stateless +@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML }) +public class JaxRsPageProviderDstu3 extends AbstractJaxRsPageProvider { + + public JaxRsPageProviderDstu3() { + super(FhirContext.forDstu3()); + } + + @Override + public IPagingProvider getPagingProvider() { + return JaxRsPatientRestProviderDstu3.PAGE_PROVIDER; + } + +} diff --git a/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientRestProviderDstu3.java b/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientRestProviderDstu3.java new file mode 100644 index 00000000000..a625becd8ad --- /dev/null +++ b/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientRestProviderDstu3.java @@ -0,0 +1,258 @@ +package ca.uhn.fhir.jaxrs.server.example; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +import javax.ejb.Local; +import javax.ejb.Stateless; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.hl7.fhir.dstu3.model.Condition; +import org.hl7.fhir.dstu3.model.HumanName; +import org.hl7.fhir.dstu3.model.IdType; +import org.hl7.fhir.dstu3.model.Parameters; +import org.hl7.fhir.dstu3.model.Patient; +import org.hl7.fhir.dstu3.model.StringType; +import org.hl7.fhir.instance.model.api.IBaseResource; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider; +import ca.uhn.fhir.rest.annotation.ConditionalUrlParam; +import ca.uhn.fhir.rest.annotation.Create; +import ca.uhn.fhir.rest.annotation.Delete; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Operation; +import ca.uhn.fhir.rest.annotation.OperationParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.ResourceParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.annotation.Update; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.api.RequestTypeEnum; +import ca.uhn.fhir.rest.api.RestOperationTypeEnum; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.server.AddProfileTagEnum; +import ca.uhn.fhir.rest.server.BundleInclusionRule; +import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.ETagSupportEnum; +import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider; +import ca.uhn.fhir.rest.server.IPagingProvider; +import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; +import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; + +/** + * A demo JaxRs Patient Rest Provider + * + * @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare + */ +@Local +@Path(JaxRsPatientRestProviderDstu3.PATH) +@Stateless +@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML }) +public class JaxRsPatientRestProviderDstu3 extends AbstractJaxRsResourceProvider { + + private static Long counter = 1L; + + /** + * The HAPI paging provider for this server + */ + public static final IPagingProvider PAGE_PROVIDER; + + static final String PATH = "/Patient"; + private static final ConcurrentHashMap> patients = new ConcurrentHashMap>(); + + static { + PAGE_PROVIDER = new FifoMemoryPagingProvider(10); + } + + static { + patients.put(String.valueOf(counter), createPatient("Van Houte")); + patients.put(String.valueOf(counter), createPatient("Agnew")); + for (int i = 0; i < 20; i++) { + patients.put(String.valueOf(counter), createPatient("Random Patient " + counter)); + } + } + + public JaxRsPatientRestProviderDstu3() { + super(FhirContext.forDstu3(), JaxRsPatientRestProviderDstu3.class); + } + + @Create + public MethodOutcome create(@ResourceParam final Patient patient, @ConditionalUrlParam String theConditional) throws Exception { + patients.put("" + counter, createPatient(patient)); + final MethodOutcome result = new MethodOutcome().setCreated(true); + result.setResource(patient); + result.setId(new IdType(patient.getId())); + return result; + } + + @Delete + public MethodOutcome delete(@IdParam final IdType theId) { + final Patient deletedPatient = find(theId); + patients.remove(deletedPatient.getIdElement().getIdPart()); + final MethodOutcome result = new MethodOutcome().setCreated(true); + result.setResource(deletedPatient); + return result; + } + + @Read + public Patient find(@IdParam final IdType theId) { + if (patients.containsKey(theId.getIdPart())) { + return getLast(patients.get(theId.getIdPart())); + } else { + throw new ResourceNotFoundException(theId); + } + } + + @Read(version = true) + public Patient findHistory(@IdParam final IdType theId) { + if (patients.containsKey(theId.getIdPart())) { + final List list = patients.get(theId.getIdPart()); + for (final Patient patient : list) { + if (patient.getIdElement().getVersionIdPartAsLong().equals(theId.getVersionIdPartAsLong())) { + return patient; + } + } + } + throw new ResourceNotFoundException(theId); + } + + @Operation(name = "firstVersion", idempotent = true, returnParameters = { @OperationParam(name = "return", type = StringType.class) }) + public Parameters firstVersion(@IdParam final IdType theId, @OperationParam(name = "dummy") StringType dummyInput) { + Parameters parameters = new Parameters(); + Patient patient = find(new IdType(theId.getResourceType(), theId.getIdPart(), "0")); + parameters.addParameter().setName("return").setResource(patient).setValue(new StringType((counter - 1) + "" + "inputVariable [ " + dummyInput.getValue() + "]")); + return parameters; + } + + @Override + public AddProfileTagEnum getAddProfileTag() { + return AddProfileTagEnum.NEVER; + } + + @Override + public BundleInclusionRule getBundleInclusionRule() { + return BundleInclusionRule.BASED_ON_INCLUDES; + } + + @Override + public ETagSupportEnum getETagSupport() { + return ETagSupportEnum.DISABLED; + } + + /** THE DEFAULTS */ + + @Override + public List getInterceptors() { + return Collections.emptyList(); + } + + private Patient getLast(final List list) { + return list.get(list.size() - 1); + } + + @Override + public IPagingProvider getPagingProvider() { + return PAGE_PROVIDER; + } + + @Override + public Class getResourceType() { + return Patient.class; + } + + @Override + public boolean isDefaultPrettyPrint() { + return true; + } + + @Override + public boolean isUseBrowserFriendlyContentTypes() { + return true; + } + + @GET + @Path("/{id}/$firstVersion") + public Response operationFirstVersionUsingGet(@PathParam("id") String id) throws IOException { + return customOperation(null, RequestTypeEnum.GET, id, "$firstVersion", RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE); + } + + @POST + @Path("/{id}/$firstVersion") + public Response operationFirstVersionUsingGet(@PathParam("id") String id, final String resource) throws Exception { + return customOperation(resource, RequestTypeEnum.POST, id, "$firstVersion", RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE); + } + + @Search + public List search(@RequiredParam(name = Patient.SP_NAME) final StringParam name) { + final List result = new LinkedList(); + for (final List patientIterator : patients.values()) { + Patient single = null; + for (Patient patient : patientIterator) { + if (name == null || patient.getName().get(0).getFamily().get(0).getValueNotNull().equals(name.getValueNotNull())) { + single = patient; + } + } + if (single != null) { + result.add(single); + } + } + return result; + } + + @Search(compartmentName = "Condition") + public List searchCompartment(@IdParam IdType thePatientId) { + List retVal = new ArrayList(); + Condition condition = new Condition(); + condition.setId(new IdType("665577")); + retVal.add(condition); + return retVal; + } + + @Update + public MethodOutcome update(@IdParam final IdType theId, @ResourceParam final Patient patient) { + final String idPart = theId.getIdPart(); + if (patients.containsKey(idPart)) { + final List patientList = patients.get(idPart); + final Patient lastPatient = getLast(patientList); + patient.setId(createId(theId.getIdPartAsLong(), lastPatient.getIdElement().getVersionIdPartAsLong() + 1)); + patientList.add(patient); + final MethodOutcome result = new MethodOutcome().setCreated(false); + result.setResource(patient); + result.setId(new IdType(patient.getId())); + return result; + } else { + throw new ResourceNotFoundException(theId); + } + } + + private static IdType createId(final Long id, final Long theVersionId) { + return new IdType("Patient", "" + id, "" + theVersionId); + } + + private static List createPatient(final Patient patient) { + patient.setId(createId(counter, 1L)); + final LinkedList list = new LinkedList(); + list.add(patient); + counter++; + return list; + } + + private static List createPatient(final String name) { + final Patient patient = new Patient(); + patient.getName().add(new HumanName().addFamily(name)); + return createPatient(patient); + } + +} diff --git a/hapi-fhir-jaxrsserver-example/src/test/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientProviderDstu3Test.java b/hapi-fhir-jaxrsserver-example/src/test/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientProviderDstu3Test.java new file mode 100644 index 00000000000..bc01e6e6755 --- /dev/null +++ b/hapi-fhir-jaxrsserver-example/src/test/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientProviderDstu3Test.java @@ -0,0 +1,315 @@ +package ca.uhn.fhir.jaxrs.server.example; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.hl7.fhir.dstu3.model.Bundle; +import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent; +import org.hl7.fhir.dstu3.model.Conformance; +import org.hl7.fhir.dstu3.model.DateType; +import org.hl7.fhir.dstu3.model.HumanName; +import org.hl7.fhir.dstu3.model.IdType; +import org.hl7.fhir.dstu3.model.Parameters; +import org.hl7.fhir.dstu3.model.Patient; +import org.hl7.fhir.dstu3.model.StringType; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.jaxrs.client.JaxRsRestfulClientFactory; +import ca.uhn.fhir.model.api.BundleEntry; +import ca.uhn.fhir.model.primitive.BoundCodeDt; +import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.api.PreferReturnEnum; +import ca.uhn.fhir.rest.client.IGenericClient; +import ca.uhn.fhir.rest.client.ServerValidationModeEnum; +import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; +import ca.uhn.fhir.rest.method.SearchStyleEnum; +import ca.uhn.fhir.rest.server.EncodingEnum; + +public class JaxRsPatientProviderDstu3Test { + + private static IGenericClient client; + private static final FhirContext ourCtx = FhirContext.forDstu3(); + private static final String PATIENT_NAME = "Van Houte"; + private static int ourPort; + private static Server jettyServer; + + @BeforeClass + public static void setUpClass() + throws Exception { + ourPort = RandomServerPortProvider.findFreePort(); + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/"); + System.out.println(ourPort); + jettyServer = new Server(ourPort); + jettyServer.setHandler(context); + ServletHolder jerseyServlet = context.addServlet(org.glassfish.jersey.servlet.ServletContainer.class, "/*"); + jerseyServlet.setInitOrder(0); + //@formatter:off + jerseyServlet.setInitParameter("jersey.config.server.provider.classnames", + StringUtils.join(Arrays.asList( + JaxRsConformanceProviderDstu3.class.getCanonicalName(), + JaxRsPatientRestProviderDstu3.class.getCanonicalName(), + JaxRsPageProviderDstu3.class.getCanonicalName() + ), ";")); + //@formatter:on + jettyServer.start(); + + ourCtx.setRestfulClientFactory(new JaxRsRestfulClientFactory(ourCtx)); + ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); + ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); + client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/"); + client.setEncoding(EncodingEnum.JSON); + client.registerInterceptor(new LoggingInterceptor(true)); + } + + @AfterClass + public static void tearDownClass() + throws Exception { + try { + jettyServer.destroy(); + } + catch (Exception e) { + } + } + + /** Search/Query - Type */ + @Test + public void findUsingGenericClientBySearch() { + // Perform a search + final Bundle results = client.search().forResource(Patient.class) + .where(Patient.NAME.matchesExactly().value(PATIENT_NAME)).returnBundle(Bundle.class).execute(); + System.out.println(results.getEntry().get(0)); + assertEquals(results.getEntry().size(), 1); + } + + /** Search - Multi-valued Parameters (ANY/OR) */ + @Test + public void findUsingGenericClientBySearchWithMultiValues() { + final Bundle response = client.search().forResource(Patient.class) + .where(Patient.ADDRESS.matches().values("Toronto")).and(Patient.ADDRESS.matches().values("Ontario")) + .and(Patient.ADDRESS.matches().values("Canada")) + .where(Patient.IDENTIFIER.exactly().systemAndIdentifier("SHORTNAME", "TOYS")).returnBundle(Bundle.class).execute(); + System.out.println(response.getEntry().get(0)); + } + + /** Search - Paging */ + @Test + public void findWithPaging() { + // Perform a search + final Bundle results = client.search().forResource(Patient.class).limitTo(8).returnBundle(Bundle.class).execute(); + System.out.println(results.getEntry().size()); + + if (results.getLink(Bundle.LINK_NEXT) != null) { + + // load next page + final Bundle nextPage = client.loadPage().next(results).execute(); + System.out.println(nextPage.getEntry().size()); + } + } + + /** Search using other query options */ + public void testOther() { + //missing + } + + /** */ + @Test + public void testSearchPost() { + Bundle response = client.search() + .forResource("Patient") + .usingStyle(SearchStyleEnum.POST) + .returnBundle(Bundle.class) + .execute(); + assertTrue(response.getEntry().size() > 0); + } + + /** Search - Compartments */ + @Test + public void testSearchCompartements() { + Bundle response = client.search() + .forResource(Patient.class) + .withIdAndCompartment("1", "Condition") + .returnBundle(Bundle.class) + .execute(); + assertTrue(response.getEntry().size() > 0); + } + + /** Search - Subsetting (_summary and _elements) */ + @Test + @Ignore + public void testSummary() { + client.search() + .forResource(Patient.class) + .returnBundle(Bundle.class) + .execute(); + } + + @Test + public void testCreatePatient() { + final Patient existing = new Patient(); + existing.setId((IdType) null); + existing.getName().add(new HumanName().addFamily("Created Patient 54")); + client.setEncoding(EncodingEnum.JSON); + final MethodOutcome results = client.create().resource(existing).prefer(PreferReturnEnum.REPRESENTATION).execute(); + System.out.println(results.getId()); + final Patient patient = (Patient) results.getResource(); + System.out.println(patient); + assertNotNull(client.read(Patient.class, patient.getId())); + client.setEncoding(EncodingEnum.JSON); + } + + + /** Conditional Creates */ + @Test + public void testConditionalCreate() { + final Patient existing = new Patient(); + existing.setId((IdType) null); + existing.getName().add(new HumanName().addFamily("Created Patient 54")); + client.setEncoding(EncodingEnum.XML); + final MethodOutcome results = client.create().resource(existing).prefer(PreferReturnEnum.REPRESENTATION).execute(); + System.out.println(results.getId()); + final Patient patient = (Patient) results.getResource(); + + client.create() + .resource(patient) + .conditional() + .where(Patient.IDENTIFIER.exactly().identifier(patient.getId())) + .execute(); + } + + + /** Find By Id */ + @Test + public void findUsingGenericClientById() { + final Patient results = client.read(Patient.class, "1"); + assertEquals(results.getIdElement().getIdPartAsLong().longValue(), 1L); + } + + @Test + public void testUpdateById() { + final Patient existing = client.read(Patient.class, "1"); + final List name = existing.getName(); + name.get(0).addSuffix("The Second"); + existing.getName().addAll(name); + client.setEncoding(EncodingEnum.XML); + final MethodOutcome results = client.update("1", existing); + } + + @Test + public void testDeletePatient() { + final Patient existing = new Patient(); + existing.getName().add(new HumanName().addFamily("Created Patient XYZ")); + final MethodOutcome results = client.create().resource(existing).prefer(PreferReturnEnum.REPRESENTATION).execute(); + System.out.println(results.getId()); + final Patient patient = (Patient) results.getResource(); + client.delete(Patient.class, patient.getId()); + try { + client.read(Patient.class, patient.getId()); + fail(); + } + catch (final Exception e) { + //assertEquals(e.getStatusCode(), Constants.STATUS_HTTP_404_NOT_FOUND); + } + } + + /** Transaction - Server */ + @Ignore + @Test + public void testTransaction() { + Bundle bundle = new Bundle(); + BundleEntryComponent entry = bundle.addEntry(); + final Patient existing = new Patient(); + existing.getName().get(0).addFamily("Created with bundle"); + entry.setResource(existing); + + // FIXME ? +// BoundCodeDt theTransactionOperation = +// new BoundCodeDt( +// BundleEntryTransactionMethodEnum.VALUESET_BINDER, +// BundleEntryTransactionMethodEnum.POST); +// entry.setTransactionMethod(theTransactionOperation); + Bundle response = client.transaction().withBundle(bundle).execute(); + } + + /** Conformance - Server */ + @Test + @Ignore + public void testConformance() { + final Conformance conf = client.fetchConformance().ofType(Conformance.class).execute(); + System.out.println(conf.getRest().get(0).getResource().get(0).getType()); + assertEquals(conf.getRest().get(0).getResource().get(0).getType().toString(), "Patient"); + } + + /** Extended Operations */ + // Create a client to talk to the HeathIntersections server + @Test + public void testExtendedOperations() { + client.registerInterceptor(new LoggingInterceptor(true)); + + // Create the input parameters to pass to the server + Parameters inParams = new Parameters(); + inParams.addParameter().setName("start").setValue(new DateType("2001-01-01")); + inParams.addParameter().setName("end").setValue(new DateType("2015-03-01")); + inParams.addParameter().setName("dummy").setValue(new StringType("myAwesomeDummyValue")); + + // Invoke $everything on "Patient/1" + Parameters outParams = client + .operation() + .onInstance(new IdType("Patient", "1")) + .named("$firstVersion") + .withParameters(inParams) + //.useHttpGet() // Use HTTP GET instead of POST + .execute(); + String resultValue = outParams.getParameter().get(0).getValue().toString(); + System.out.println(resultValue); + assertEquals("expected but found : "+ resultValue, resultValue.contains("myAwesomeDummyValue"), true); + } + + @Test + public void testExtendedOperationsUsingGet() { + // Create the input parameters to pass to the server + Parameters inParams = new Parameters(); + inParams.addParameter().setName("start").setValue(new DateType("2001-01-01")); + inParams.addParameter().setName("end").setValue(new DateType("2015-03-01")); + inParams.addParameter().setName("dummy").setValue(new StringType("myAwesomeDummyValue")); + + // Invoke $everything on "Patient/1" + Parameters outParams = client + .operation() + .onInstance(new IdType("Patient", "1")) + .named("$firstVersion") + .withParameters(inParams) + .useHttpGet() // Use HTTP GET instead of POST + .execute(); + String resultValue = outParams.getParameter().get(0).getValue().toString(); + System.out.println(resultValue); + assertEquals("expected but found : "+ resultValue, resultValue.contains("myAwesomeDummyValue"), true); + } + + @Test + public void testVRead() { + final Patient patient = client.vread(Patient.class, "1", "1"); + System.out.println(patient); + } + + @Test + public void testRead() { + final Patient patient = client.read(Patient.class, "1"); + System.out.println(patient); + } + +}