diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseJpaResourceProviderValueSetDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseJpaResourceProviderValueSetDstu2.java index 786c4d29bb6..fcf7efcfb5b 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseJpaResourceProviderValueSetDstu2.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseJpaResourceProviderValueSetDstu2.java @@ -24,6 +24,8 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank; import javax.servlet.http.HttpServletRequest; +import org.apache.commons.lang3.BooleanUtils; + import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet; import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult; import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt; @@ -38,6 +40,7 @@ import ca.uhn.fhir.model.primitive.UriDt; 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.server.exceptions.InvalidRequestException; public class BaseJpaResourceProviderValueSetDstu2 extends JpaResourceProviderDstu2 { @@ -45,58 +48,55 @@ public class BaseJpaResourceProviderValueSetDstu2 extends JpaResourceProviderDst @Operation(name = "$expand", idempotent = true) public ValueSet expant( HttpServletRequest theServletRequest, - - @IdParam IdDt theId, - + @IdParam(optional=true) IdDt theId, + @OperationParam(name="valueSet", min=0, max=1) ValueSet theValueSet, + @OperationParam(name="identifier", min=0, max=1) UriDt theIdentifier, @OperationParam(name = "filter", min=0, max=1) StringDt theFilter) { //@formatter:on + boolean haveId = theId != null && theId.hasIdPart(); + boolean haveIdentifier = theIdentifier != null && isNotBlank(theIdentifier.getValue()); + boolean haveValueSet = theValueSet != null && theValueSet.isEmpty() == false; + + if (!haveId && !haveIdentifier && !haveValueSet) { + throw new InvalidRequestException("$expand operation at the type level (no ID specified) requires an identifier or a valueSet as a part of the request"); + } + + if (moreThanOneTrue(haveId, haveIdentifier, haveValueSet)) { + throw new InvalidRequestException("$expand must EITHER be invoked at the type level, or have an identifier specified, or have a ValueSet specified. Can not combine these options."); + } + startRequest(theServletRequest); try { IFhirResourceDaoValueSet dao = (IFhirResourceDaoValueSet) getDao(); - return dao.expand(theId, toFilterString(theFilter)); + if (haveId) { + return dao.expand(theId, toFilterString(theFilter)); + } else if (haveIdentifier) { + return dao.expandByIdentifier(theIdentifier.getValue(), toFilterString(theFilter)); + } else { + return dao.expand(theValueSet, toFilterString(theFilter)); + } + } finally { endRequest(theServletRequest); } } - //@formatter:off - @Operation(name = "$expand", idempotent = true) - public ValueSet everything( - HttpServletRequest theServletRequest, - @OperationParam(name="identifier", min=1, max=1) UriDt theIdentifier, - - @OperationParam(name = "filter", min=0, max=1) StringDt theFilter) { - //@formatter:on - - startRequest(theServletRequest); - try { - IFhirResourceDaoValueSet dao = (IFhirResourceDaoValueSet) getDao(); - return dao.expandByIdentifier(theIdentifier.getValue(), toFilterString(theFilter)); - } finally { - endRequest(theServletRequest); + private static boolean moreThanOneTrue(boolean... theBooleans) { + boolean haveOne = false; + for (boolean next : theBooleans) { + if (next) { + if (haveOne) { + return true; + } else { + haveOne = true; + } + } } + return false; } - //@formatter:off - @Operation(name = "$expand", idempotent = true) - public ValueSet everything( - HttpServletRequest theServletRequest, - - @OperationParam(name="valueSet", min=1, max=1) ValueSet theValueSet, - - @OperationParam(name = "filter", min=0, max=1) StringDt theFilter) { - //@formatter:on - - startRequest(theServletRequest); - try { - IFhirResourceDaoValueSet dao = (IFhirResourceDaoValueSet) getDao(); - return dao.expand(theValueSet, toFilterString(theFilter)); - } finally { - endRequest(theServletRequest); - } - } private String toFilterString(StringDt theFilter) { return theFilter != null ? theFilter.getValue() : null; diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2ValueSetTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2ValueSetTest.java index e89eeeadd98..f592ea22dcd 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2ValueSetTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2ValueSetTest.java @@ -3,7 +3,9 @@ package ca.uhn.fhir.jpa.provider; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.stringContainsInOrder; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; import java.io.IOException; @@ -16,6 +18,7 @@ import ca.uhn.fhir.model.dstu2.resource.Parameters; import ca.uhn.fhir.model.dstu2.resource.ValueSet; import ca.uhn.fhir.model.primitive.StringDt; import ca.uhn.fhir.model.primitive.UriDt; +import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; public class ResourceProviderDstu2ValueSetTest extends BaseResourceProviderDstu2Test { @@ -157,5 +160,54 @@ public class ResourceProviderDstu2ValueSetTest extends BaseResourceProviderDstu2 assertThat(resp, not(containsString(""))); } + @Test + public void testExpandInvalidParams() throws IOException { + //@formatter:off + try { + ourClient + .operation() + .onType(ValueSet.class) + .named("expand") + .withNoParameters(Parameters.class) + .execute(); + fail(); + } catch (InvalidRequestException e) { + assertEquals("HTTP 400 Bad Request: $expand operation at the type level (no ID specified) requires an identifier or a valueSet as a part of the request", e.getMessage()); + } + //@formatter:on + + //@formatter:off + try { + ValueSet toExpand = loadResourceFromClasspath(ValueSet.class, "/extensional-case-2.xml"); + ourClient + .operation() + .onType(ValueSet.class) + .named("expand") + .withParameter(Parameters.class, "valueSet", toExpand) + .andParameter("identifier", new UriDt("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2")) + .execute(); + fail(); + } catch (InvalidRequestException e) { + assertEquals("HTTP 400 Bad Request: $expand must EITHER be invoked at the type level, or have an identifier specified, or have a ValueSet specified. Can not combine these options.", e.getMessage()); + } + //@formatter:on + + //@formatter:off + try { + ValueSet toExpand = loadResourceFromClasspath(ValueSet.class, "/extensional-case-2.xml"); + ourClient + .operation() + .onInstance(myExtensionalVsId) + .named("expand") + .withParameter(Parameters.class, "valueSet", toExpand) + .andParameter("identifier", new UriDt("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2")) + .execute(); + fail(); + } catch (InvalidRequestException e) { + assertEquals("HTTP 400 Bad Request: $expand must EITHER be invoked at the type level, or have an identifier specified, or have a ValueSet specified. Can not combine these options.", e.getMessage()); + } + //@formatter:on + + } }