From b3bb5f9052ecebce87588e2d5f5be983fbd0fd2e Mon Sep 17 00:00:00 2001 From: James Agnew Date: Thu, 10 May 2018 11:19:28 -0400 Subject: [PATCH] Parameter updates --- hapi-fhir-cli/hapi-fhir-cli-app/pom.xml | 6 ++ hapi-fhir-dist/src/assembly/hapi-fhir-cli.xml | 64 ++++++------- .../server/method/OperationParameter.java | 90 +++++++++++-------- .../rest/server/OperationServerR4Test.java | 40 +++++++++ src/changes/changes.xml | 5 ++ 5 files changed, 135 insertions(+), 70 deletions(-) diff --git a/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml index 4fb2e600800..17a9fc556a9 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml +++ b/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml @@ -17,6 +17,12 @@ + + ca.uhn.hapi.fhir + hapi-fhir-cli-api + ${project.version} + jar + ca.uhn.hapi.fhir hapi-fhir-cli-jpaserver diff --git a/hapi-fhir-dist/src/assembly/hapi-fhir-cli.xml b/hapi-fhir-dist/src/assembly/hapi-fhir-cli.xml index 28bd3358f7c..e12e59d228f 100644 --- a/hapi-fhir-dist/src/assembly/hapi-fhir-cli.xml +++ b/hapi-fhir-dist/src/assembly/hapi-fhir-cli.xml @@ -1,32 +1,32 @@ - - - - cli - - - zip - tar.bz2 - - - false - - - - ${project.basedir}/../hapi-fhir-cli/hapi-fhir-cli-app/target/ - / - - hapi-fhir-cli.jar - - - - ${project.basedir}/../hapi-fhir-cli/hapi-fhir-cli-app/src/main/script - / - - hapi-fhir-cli - hapi-fhir-cli.cmd - - 0555 - - - - + + + + cli + + + zip + tar.bz2 + + + false + + + + ${project.basedir}/../hapi-fhir-cli/hapi-fhir-cli-app/target/ + / + + hapi-fhir-cli.jar + + + + ${project.basedir}/../hapi-fhir-cli/hapi-fhir-cli-api/src/main/script + / + + hapi-fhir-cli + hapi-fhir-cli.cmd + + 0555 + + + + diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/OperationParameter.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/OperationParameter.java index 01dd657f6b4..f4798c23132 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/OperationParameter.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/OperationParameter.java @@ -1,5 +1,35 @@ package ca.uhn.fhir.rest.server.method; +import ca.uhn.fhir.context.*; +import ca.uhn.fhir.context.BaseRuntimeChildDefinition.IAccessor; +import ca.uhn.fhir.i18n.HapiLocalizer; +import ca.uhn.fhir.model.api.IDatatype; +import ca.uhn.fhir.model.api.IQueryParameterAnd; +import ca.uhn.fhir.model.api.IQueryParameterOr; +import ca.uhn.fhir.model.api.IQueryParameterType; +import ca.uhn.fhir.rest.annotation.OperationParam; +import ca.uhn.fhir.rest.api.QualifiedParamList; +import ca.uhn.fhir.rest.api.RequestTypeEnum; +import ca.uhn.fhir.rest.api.ValidationModeEnum; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.param.BaseAndListParam; +import ca.uhn.fhir.rest.param.DateRangeParam; +import ca.uhn.fhir.rest.param.binder.CollectionBinder; +import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; +import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; +import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException; +import ca.uhn.fhir.util.FhirTerser; +import ca.uhn.fhir.util.ReflectionUtil; +import org.apache.commons.lang3.Validate; +import org.hl7.fhir.instance.model.api.IBase; +import org.hl7.fhir.instance.model.api.IBaseDatatype; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.instance.model.api.IPrimitiveType; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.*; + import static org.apache.commons.lang3.StringUtils.isNotBlank; /* @@ -11,9 +41,9 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank; * 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. @@ -22,43 +52,20 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank; * #L% */ -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.*; - -import org.apache.commons.lang3.Validate; -import org.hl7.fhir.instance.model.api.*; - -import ca.uhn.fhir.context.*; -import ca.uhn.fhir.context.BaseRuntimeChildDefinition.IAccessor; -import ca.uhn.fhir.i18n.HapiLocalizer; -import ca.uhn.fhir.model.api.*; -import ca.uhn.fhir.rest.annotation.OperationParam; -import ca.uhn.fhir.rest.api.*; -import ca.uhn.fhir.rest.api.server.RequestDetails; -import ca.uhn.fhir.rest.param.*; -import ca.uhn.fhir.rest.param.binder.CollectionBinder; -import ca.uhn.fhir.rest.server.exceptions.*; -import ca.uhn.fhir.util.FhirTerser; -import ca.uhn.fhir.util.ReflectionUtil; - public class OperationParameter implements IParameter { + static final String REQUEST_CONTENTS_USERDATA_KEY = OperationParam.class.getName() + "_PARSED_RESOURCE"; @SuppressWarnings("unchecked") private static final Class[] COMPOSITE_TYPES = new Class[0]; - - static final String REQUEST_CONTENTS_USERDATA_KEY = OperationParam.class.getName() + "_PARSED_RESOURCE"; - - private boolean myAllowGet; - private final FhirContext myContext; + private final String myName; + private final String myOperationName; + private boolean myAllowGet; private IOperationParamConverter myConverter; @SuppressWarnings("rawtypes") private Class myInnerCollectionType; private int myMax; private int myMin; - private final String myName; - private final String myOperationName; private Class myParameterType; private String myParamType; private SearchParameter mySearchParameterBinding; @@ -75,7 +82,7 @@ public class OperationParameter implements IParameter { myContext = theCtx; } - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings({"rawtypes", "unchecked"}) private void addValueToList(List matchingParamValues, Object values) { if (values != null) { if (BaseAndListParam.class.isAssignableFrom(myParameterType) && matchingParamValues.size() > 0) { @@ -145,10 +152,10 @@ public class OperationParameter implements IParameter { boolean typeIsConcrete = !myParameterType.isInterface() && !Modifier.isAbstract(myParameterType.getModifiers()); //@formatter:off - boolean isSearchParam = - IQueryParameterType.class.isAssignableFrom(myParameterType) || - IQueryParameterOr.class.isAssignableFrom(myParameterType) || - IQueryParameterAnd.class.isAssignableFrom(myParameterType); + boolean isSearchParam = + IQueryParameterType.class.isAssignableFrom(myParameterType) || + IQueryParameterOr.class.isAssignableFrom(myParameterType) || + IQueryParameterAnd.class.isAssignableFrom(myParameterType); //@formatter:off /* @@ -250,7 +257,7 @@ public class OperationParameter implements IParameter { Object values = mySearchParameterBinding.parse(myContext, Collections.singletonList(next)); addValueToList(matchingParamValues, values); } - + } } else { @@ -274,7 +281,7 @@ public class OperationParameter implements IParameter { matchingParamValues.add(next); } } else if (ValidationModeEnum.class.equals(myParameterType)) { - + if (isNotBlank(paramValues[0])) { ValidationModeEnum validationMode = ValidationModeEnum.forCode(paramValues[0]); if (validationMode != null) { @@ -283,7 +290,7 @@ public class OperationParameter implements IParameter { throwInvalidMode(paramValues[0]); } } - + } else { for (String nextValue : paramValues) { FhirContext ctx = theRequest.getServer().getFhirContext(); @@ -356,6 +363,13 @@ public class OperationParameter implements IParameter { if (myConverter != null) { nextValue = myConverter.incomingServer(nextValue); } + if (myParameterType.equals(String.class)) { + if (nextValue instanceof IPrimitiveType) { + IPrimitiveType source = (IPrimitiveType) nextValue; + theMatchingParamValues.add(source.getValueAsString()); + continue; + } + } if (!myParameterType.isAssignableFrom(nextValue.getClass())) { Class sourceType = (Class) nextValue.getClass(); Class targetType = (Class) myParameterType; @@ -373,7 +387,7 @@ public class OperationParameter implements IParameter { } throwWrongParamType(nextValue); } - + addValueToList(theMatchingParamValues, nextValue); } } diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/OperationServerR4Test.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/OperationServerR4Test.java index 2be3de6a47c..ba793c3fc53 100644 --- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/OperationServerR4Test.java +++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/OperationServerR4Test.java @@ -338,6 +338,29 @@ public class OperationServerR4Test { assertEquals("RET1", resp.getParameter().get(0).getName()); } + @Test + public void testOperationOnServerWithRawString() throws Exception { + Parameters p = new Parameters(); + p.addParameter().setName("PARAM1").setValue(new StringType("PARAM1val")); + p.addParameter().setName("PARAM2").setResource(new Patient().setActive(true)); + String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/$OP_SERVER_WITH_RAW_STRING"); + httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + HttpResponse status = ourClient.execute(httpPost); + + assertEquals(200, status.getStatusLine().getStatusCode()); + String response = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals("PARAM1val", ourLastParam1.getValue()); + assertEquals(true, ourLastParam2.getActive()); + assertEquals("$OP_SERVER", ourLastMethod); + + Parameters resp = ourCtx.newXmlParser().parseResource(Parameters.class, response); + assertEquals("RET1", resp.getParameter().get(0).getName()); + } + @Test public void testOperationOnType() throws Exception { Parameters p = new Parameters(); @@ -763,6 +786,23 @@ public class OperationServerR4Test { return retVal; } + //@formatter:off + @Operation(name="$OP_SERVER_WITH_RAW_STRING") + public Parameters opServer( + @OperationParam(name="PARAM1") String theParam1, + @OperationParam(name="PARAM2") Patient theParam2 + ) { + //@formatter:on + + ourLastMethod = "$OP_SERVER"; + ourLastParam1 = new StringType(theParam1); + ourLastParam2 = theParam2; + + Parameters retVal = new Parameters(); + retVal.addParameter().setName("RET1").setValue(new StringType("RETVAL1")); + return retVal; + } + //@formatter:off @Operation(name="$OP_SERVER_LIST_PARAM") public Parameters opServerListParam( diff --git a/src/changes/changes.xml b/src/changes/changes.xml index b01b630bbdf..63bc86be8a4 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -127,6 +127,11 @@ Fix a bug in the DSTU2 QuestionnaireResponseValidator which prevented validation on groups with only one question. Thanks David Gileadi for the pull request! + + Operation methods on a plain server may now use parameters + of type String (i.e. plain Java strings), and any FHIR primitive + datatype will be automatically coerced into a String. +