More work on fixing #19

This commit is contained in:
jamesagnew 2014-09-03 09:08:55 -04:00
parent c704aa185d
commit 93c54f57fe
4 changed files with 148 additions and 116 deletions

View File

@ -95,8 +95,7 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
SearchParameter sp = (SearchParameter) next;
if (sp.getName().startsWith("_")) {
if (ALLOWED_PARAMS.contains(sp.getName())) {
String msg = getContext().getLocalizer().getMessage(getClass().getName() + ".invalidSpecialParamName", theMethod.getName(), theMethod.getDeclaringClass().getSimpleName(),
sp.getName());
String msg = getContext().getLocalizer().getMessage(getClass().getName() + ".invalidSpecialParamName", theMethod.getName(), theMethod.getDeclaringClass().getSimpleName(), sp.getName());
throw new ConfigurationException(msg);
}
}
@ -317,9 +316,18 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
}
if (theQualifierWhitelist != null) {
if (!theQualifierWhitelist.contains(OptionalParam.ALLOW_CHAIN_ANY)) {
if (qualifier != null) {
if (!theQualifierWhitelist.contains(qualifier)) {
continue;
if (qualifier.charAt(0) == '.') {
if (!theQualifierWhitelist.contains(".*")) {
continue;
}
}
if (qualifier.charAt(0) == ':') {
if (!theQualifierWhitelist.contains(":*")) {
continue;
}
}
}
}
}
@ -333,8 +341,7 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
return retVal;
}
public static BaseHttpClientInvocation createSearchInvocation(FhirContext theContext, String theResourceName, Map<String, List<String>> theParameters, IdDt theId, String theCompartmentName,
SearchStyleEnum theSearchStyle) {
public static BaseHttpClientInvocation createSearchInvocation(FhirContext theContext, String theResourceName, Map<String, List<String>> theParameters, IdDt theId, String theCompartmentName, SearchStyleEnum theSearchStyle) {
SearchStyleEnum searchStyle = theSearchStyle;
if (searchStyle == null) {
int length = 0;
@ -365,7 +372,8 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
}
/*
* Are we doing a get (GET [base]/Patient?name=foo) or a get with search (GET [base]/Patient/_search?name=foo) or a post (POST [base]/Patient with parameters in the POST body)
* Are we doing a get (GET [base]/Patient?name=foo) or a get with search (GET [base]/Patient/_search?name=foo)
* or a post (POST [base]/Patient with parameters in the POST body)
*/
switch (searchStyle) {
case GET:

View File

@ -80,9 +80,10 @@ import ca.uhn.fhir.util.CollectionUtil;
public class SearchParameter extends BaseQueryParameter {
private static final String EMPTY_STRING = "";
private static HashMap<Class<?>, SearchParamTypeEnum> ourParamTypes;
private static HashMap<SearchParamTypeEnum, Set<String>> ourParamQualifiers;
private static HashMap<Class<?>, SearchParamTypeEnum> ourParamTypes;
static final String QUALIFIER_ANY_TYPE = ":*";
static {
ourParamTypes = new HashMap<Class<?>, SearchParamTypeEnum>();
ourParamQualifiers = new HashMap<SearchParamTypeEnum, Set<String>>();
@ -116,21 +117,28 @@ public class SearchParameter extends BaseQueryParameter {
ourParamTypes.put(ReferenceParam.class, SearchParamTypeEnum.REFERENCE);
ourParamTypes.put(ReferenceOrListParam.class, SearchParamTypeEnum.REFERENCE);
ourParamTypes.put(ReferenceAndListParam.class, SearchParamTypeEnum.REFERENCE);
ourParamQualifiers.put(SearchParamTypeEnum.REFERENCE, CollectionUtil.newSet(Constants.PARAMQUALIFIER_MISSING)); // no empty because that gets added from OptionalParam#chainWhitelist
ourParamQualifiers.put(SearchParamTypeEnum.REFERENCE, CollectionUtil.newSet(Constants.PARAMQUALIFIER_MISSING)); // no
// empty
// because
// that
// gets
// added
// from
// OptionalParam#chainWhitelist
ourParamTypes.put(CompositeParam.class, SearchParamTypeEnum.COMPOSITE);
ourParamTypes.put(CompositeOrListParam.class, SearchParamTypeEnum.COMPOSITE);
ourParamTypes.put(CompositeAndListParam.class, SearchParamTypeEnum.COMPOSITE);
ourParamQualifiers.put(SearchParamTypeEnum.COMPOSITE, CollectionUtil.newSet(Constants.PARAMQUALIFIER_MISSING, EMPTY_STRING));
}
private Set<String> myQualifierBlacklist;
private Set<String> myQualifierWhitelist;
private List<Class<? extends IQueryParameterType>> myCompositeTypes;
private List<Class<? extends IResource>> myDeclaredTypes;
private String myDescription;
private String myName;
private IParamBinder myParamBinder;
private SearchParamTypeEnum myParamType;
private Set<String> myQualifierBlacklist;
private Set<String> myQualifierWhitelist;
private boolean myRequired;
private Class<?> myType;
@ -159,16 +167,6 @@ public class SearchParameter extends BaseQueryParameter {
return retVal;
}
@Override
public Set<String> getQualifierBlacklist() {
return myQualifierBlacklist;
}
@Override
public Set<String> getQualifierWhitelist() {
return myQualifierWhitelist;
}
public List<Class<? extends IResource>> getDeclaredTypes() {
return Collections.unmodifiableList(myDeclaredTypes);
}
@ -192,6 +190,16 @@ public class SearchParameter extends BaseQueryParameter {
return myParamType;
}
@Override
public Set<String> getQualifierBlacklist() {
return myQualifierBlacklist;
}
@Override
public Set<String> getQualifierWhitelist() {
return myQualifierWhitelist;
}
public Class<?> getType() {
return myType;
}
@ -218,12 +226,13 @@ public class SearchParameter extends BaseQueryParameter {
public void setChainlists(String[] theChainWhitelist, String[] theChainBlacklist) {
myQualifierWhitelist = new HashSet<String>(theChainWhitelist.length);
myQualifierWhitelist.add(QUALIFIER_ANY_TYPE);
for (int i = 0; i < theChainWhitelist.length; i++) {
if (theChainWhitelist[i].equals(OptionalParam.ALLOW_CHAIN_ANY)) {
myQualifierWhitelist.add(OptionalParam.ALLOW_CHAIN_ANY);
} else if (theChainWhitelist[i].equals(EMPTY_STRING)) {
myQualifierWhitelist.add(EMPTY_STRING);
myQualifierWhitelist.add("");
} else {
myQualifierWhitelist.add('.' + theChainWhitelist[i]);
}
@ -291,7 +300,7 @@ public class SearchParameter extends BaseQueryParameter {
}
}
}
if (myParamType == null) {
myParamType = typeEnum;
}

View File

@ -53,15 +53,15 @@ public abstract class BaseQueryParameter implements IParameter {
public abstract boolean isRequired();
/**
* Parameter should return true if {@link #parse(List)} should be called even if the query string contained no values for the given parameter
* Parameter should return true if {@link #parse(List)} should be called even if the query string contained no
* values for the given parameter
*/
public abstract boolean handlesMissing();
public abstract SearchParamTypeEnum getParamType();
@Override
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments,
BaseHttpClientInvocation theClientInvocation) throws InternalErrorException {
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, BaseHttpClientInvocation theClientInvocation) throws InternalErrorException {
if (theSourceClientArgument == null) {
if (isRequired()) {
throw new NullPointerException("SearchParameter '" + getName() + "' is required and may not be null");
@ -118,8 +118,19 @@ public abstract class BaseQueryParameter implements IParameter {
private void parseParams(RequestDetails theRequest, List<QualifiedParamList> paramList, String theQualifiedParamName, String theQualifier) {
if (getQualifierWhitelist() != null) {
if (!getQualifierWhitelist().contains(OptionalParam.ALLOW_CHAIN_ANY)) {
if (!getQualifierWhitelist().contains(defaultString(theQualifier))) {
if (!getQualifierWhitelist().contains(defaultString(theQualifier))) {
if (theQualifier == null) {
return;
}
if (theQualifier.charAt(0) == '.') {
if (!getQualifierWhitelist().contains(".*")) {
return;
}
} else if (theQualifier.charAt(0) == ':') {
if (!getQualifierWhitelist().contains(":*")) {
return;
}
} else {
return;
}
}

View File

@ -49,121 +49,127 @@ public class ReferenceParameterTest {
@Test
public void testSearchWithValue() throws Exception {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?" + Patient.SP_PROVIDER + "=123");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?" + Patient.SP_PROVIDER + "=123");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
List<BundleEntry> entries = ourCtx.newXmlParser().parseBundle(responseContent).getEntries();
assertEquals(1, entries.size());
Patient p = (Patient) entries.get(0).getResource();
assertEquals("0123", p.getName().get(0).getFamilyFirstRep().getValue());
assertEquals("1", p.getName().get(1).getFamilyFirstRep().getValue());
assertEquals("2", p.getName().get(2).getFamilyFirstRep().getValue());
}
assertEquals(200, status.getStatusLine().getStatusCode());
List<BundleEntry> entries = ourCtx.newXmlParser().parseBundle(responseContent).getEntries();
assertEquals(1, entries.size());
Patient p = (Patient) entries.get(0).getResource();
assertEquals("0123", p.getName().get(0).getFamilyFirstRep().getValue());
assertEquals("1", p.getName().get(1).getFamilyFirstRep().getValue());
assertEquals("2", p.getName().get(2).getFamilyFirstRep().getValue());
}
@Test
public void testSearchWithValueAndType() throws Exception {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?" + Patient.SP_PROVIDER + ":Organization=123");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?" + Patient.SP_PROVIDER + ":Organization=123");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
List<BundleEntry> entries = ourCtx.newXmlParser().parseBundle(responseContent).getEntries();
assertEquals(1, entries.size());
Patient p = (Patient) entries.get(0).getResource();
assertEquals("0123", p.getName().get(0).getFamilyFirstRep().getValue());
assertEquals("1Organization", p.getName().get(1).getFamilyFirstRep().getValue());
assertEquals("2", p.getName().get(2).getFamilyFirstRep().getValue());
}
assertEquals(200, status.getStatusLine().getStatusCode());
List<BundleEntry> entries = ourCtx.newXmlParser().parseBundle(responseContent).getEntries();
assertEquals(1, entries.size());
Patient p = (Patient) entries.get(0).getResource();
assertEquals("0123", p.getName().get(0).getFamilyFirstRep().getValue());
assertEquals("1Organization", p.getName().get(1).getFamilyFirstRep().getValue());
assertEquals("2", p.getName().get(2).getFamilyFirstRep().getValue());
}
@Test
public void testSearchWithValueAndTypeAndChain() throws Exception {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?" + Patient.SP_PROVIDER + ":Organization.name=123");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?" + Patient.SP_PROVIDER + ":Organization.name=123");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
List<BundleEntry> entries = ourCtx.newXmlParser().parseBundle(responseContent).getEntries();
assertEquals(1, entries.size());
Patient p = (Patient) entries.get(0).getResource();
assertEquals("0123", p.getName().get(0).getFamilyFirstRep().getValue());
assertEquals("1Organization", p.getName().get(1).getFamilyFirstRep().getValue());
assertEquals("2name", p.getName().get(2).getFamilyFirstRep().getValue());
assertEquals(200, status.getStatusLine().getStatusCode());
List<BundleEntry> entries = ourCtx.newXmlParser().parseBundle(responseContent).getEntries();
assertEquals(1, entries.size());
Patient p = (Patient) entries.get(0).getResource();
assertEquals("0123", p.getName().get(0).getFamilyFirstRep().getValue());
assertEquals("1Organization", p.getName().get(1).getFamilyFirstRep().getValue());
assertEquals("2name", p.getName().get(2).getFamilyFirstRep().getValue());
}
}
@Test
public void testSearchWithMultipleParamsOfTheSameName1() throws Exception {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof=po123");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("value=\"thePartOfId po123 null\""));
}
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof=po123");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("value=\"thePartOfId po123 null\""));
}
@Test
public void testSearchWithMultipleParamsOfTheSameName2() throws Exception {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof.name=poname");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("value=\"thePartOfName poname\""));
}
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof.name=poname");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("value=\"thePartOfName poname\""));
}
@Test
public void testSearchWithMultipleParamsOfTheSameName3() throws Exception {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof=po123&partof.name=poname");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("value=\"thePartOfId po123 null\""));
assertThat(responseContent, containsString("value=\"thePartOfName poname\""));
}
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof=po123&partof.name=poname");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("value=\"thePartOfId po123 null\""));
assertThat(responseContent, containsString("value=\"thePartOfName poname\""));
}
@Test
public void testSearchWithMultipleParamsOfTheSameName4() throws Exception {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof.fooChain=po123&partof.name=poname");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("value=\"thePartOfId po123 fooChain\""));
assertThat(responseContent, containsString("value=\"thePartOfName poname\""));
}
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof.fooChain=po123&partof.name=poname");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("value=\"thePartOfId po123 fooChain\""));
assertThat(responseContent, containsString("value=\"thePartOfName poname\""));
}
@Test
public void testSearchWithMultipleParamsOfTheSameName5() throws Exception {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof.bar=po123");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("value=\"theBarId po123 bar\""));
}
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof.bar=po123");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("value=\"theBarId po123 bar\""));
}
@Test
public void testSearchWithMultipleParamsOfTheSameName6() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof:Organization.bar=po123");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("value=\"theBarId po123 bar\""));
}
@Test
public void testSearchWithMultipleParamsOfTheSameName7() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof:Organization=po123");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("value=\"thePartOfId po123 null\""));
}
@Test
public void testSearchWithValueAndChain() throws Exception {
{
@ -221,9 +227,7 @@ public class ReferenceParameterTest {
ServletHandler proxyHandler = new ServletHandler();
RestfulServer servlet = new RestfulServer();
ourCtx = servlet.getFhirContext();
servlet.setResourceProviders(patientProvider
, new DummyOrganizationResourceProvider()
);
servlet.setResourceProviders(patientProvider, new DummyOrganizationResourceProvider());
ServletHolder servletHolder = new ServletHolder(servlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler);
@ -245,7 +249,7 @@ public class ReferenceParameterTest {
}
/**
* https://github.com/jamesagnew/hapi-fhir/issues/18
* https://github.com/jamesagnew/hapi-fhir/issues/19
*/
//@formatter:off
@Search