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; SearchParameter sp = (SearchParameter) next;
if (sp.getName().startsWith("_")) { if (sp.getName().startsWith("_")) {
if (ALLOWED_PARAMS.contains(sp.getName())) { if (ALLOWED_PARAMS.contains(sp.getName())) {
String msg = getContext().getLocalizer().getMessage(getClass().getName() + ".invalidSpecialParamName", theMethod.getName(), theMethod.getDeclaringClass().getSimpleName(), String msg = getContext().getLocalizer().getMessage(getClass().getName() + ".invalidSpecialParamName", theMethod.getName(), theMethod.getDeclaringClass().getSimpleName(), sp.getName());
sp.getName());
throw new ConfigurationException(msg); throw new ConfigurationException(msg);
} }
} }
@ -317,11 +316,20 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
} }
if (theQualifierWhitelist != null) { if (theQualifierWhitelist != null) {
if (!theQualifierWhitelist.contains(OptionalParam.ALLOW_CHAIN_ANY)) { if (qualifier != null) {
if (!theQualifierWhitelist.contains(qualifier)) { if (!theQualifierWhitelist.contains(qualifier)) {
if (qualifier.charAt(0) == '.') {
if (!theQualifierWhitelist.contains(".*")) {
continue; continue;
} }
} }
if (qualifier.charAt(0) == ':') {
if (!theQualifierWhitelist.contains(":*")) {
continue;
}
}
}
}
} }
if (theQualifierBlacklist != null) { if (theQualifierBlacklist != null) {
if (theQualifierBlacklist.contains(qualifier)) { if (theQualifierBlacklist.contains(qualifier)) {
@ -333,8 +341,7 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
return retVal; return retVal;
} }
public static BaseHttpClientInvocation createSearchInvocation(FhirContext theContext, String theResourceName, Map<String, List<String>> theParameters, IdDt theId, String theCompartmentName, public static BaseHttpClientInvocation createSearchInvocation(FhirContext theContext, String theResourceName, Map<String, List<String>> theParameters, IdDt theId, String theCompartmentName, SearchStyleEnum theSearchStyle) {
SearchStyleEnum theSearchStyle) {
SearchStyleEnum searchStyle = theSearchStyle; SearchStyleEnum searchStyle = theSearchStyle;
if (searchStyle == null) { if (searchStyle == null) {
int length = 0; 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) { switch (searchStyle) {
case GET: case GET:

View File

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

View File

@ -53,15 +53,15 @@ public abstract class BaseQueryParameter implements IParameter {
public abstract boolean isRequired(); 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 boolean handlesMissing();
public abstract SearchParamTypeEnum getParamType(); public abstract SearchParamTypeEnum getParamType();
@Override @Override
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, BaseHttpClientInvocation theClientInvocation) throws InternalErrorException {
BaseHttpClientInvocation theClientInvocation) throws InternalErrorException {
if (theSourceClientArgument == null) { if (theSourceClientArgument == null) {
if (isRequired()) { if (isRequired()) {
throw new NullPointerException("SearchParameter '" + getName() + "' is required and may not be null"); 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) { private void parseParams(RequestDetails theRequest, List<QualifiedParamList> paramList, String theQualifiedParamName, String theQualifier) {
if (getQualifierWhitelist() != null) { 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; return;
} }
} }

View File

@ -49,7 +49,6 @@ public class ReferenceParameterTest {
@Test @Test
public void testSearchWithValue() throws Exception { public void testSearchWithValue() throws Exception {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?" + Patient.SP_PROVIDER + "=123"); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?" + Patient.SP_PROVIDER + "=123");
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent()); String responseContent = IOUtils.toString(status.getEntity().getContent());
@ -64,11 +63,9 @@ public class ReferenceParameterTest {
assertEquals("1", p.getName().get(1).getFamilyFirstRep().getValue()); assertEquals("1", p.getName().get(1).getFamilyFirstRep().getValue());
assertEquals("2", p.getName().get(2).getFamilyFirstRep().getValue()); assertEquals("2", p.getName().get(2).getFamilyFirstRep().getValue());
} }
}
@Test @Test
public void testSearchWithValueAndType() throws Exception { public void testSearchWithValueAndType() throws Exception {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?" + Patient.SP_PROVIDER + ":Organization=123"); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?" + Patient.SP_PROVIDER + ":Organization=123");
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent()); String responseContent = IOUtils.toString(status.getEntity().getContent());
@ -82,11 +79,9 @@ public class ReferenceParameterTest {
assertEquals("1Organization", p.getName().get(1).getFamilyFirstRep().getValue()); assertEquals("1Organization", p.getName().get(1).getFamilyFirstRep().getValue());
assertEquals("2", p.getName().get(2).getFamilyFirstRep().getValue()); assertEquals("2", p.getName().get(2).getFamilyFirstRep().getValue());
} }
}
@Test @Test
public void testSearchWithValueAndTypeAndChain() throws Exception { public void testSearchWithValueAndTypeAndChain() throws Exception {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?" + Patient.SP_PROVIDER + ":Organization.name=123"); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?" + Patient.SP_PROVIDER + ":Organization.name=123");
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent()); String responseContent = IOUtils.toString(status.getEntity().getContent());
@ -99,12 +94,11 @@ public class ReferenceParameterTest {
assertEquals("0123", p.getName().get(0).getFamilyFirstRep().getValue()); assertEquals("0123", p.getName().get(0).getFamilyFirstRep().getValue());
assertEquals("1Organization", p.getName().get(1).getFamilyFirstRep().getValue()); assertEquals("1Organization", p.getName().get(1).getFamilyFirstRep().getValue());
assertEquals("2name", p.getName().get(2).getFamilyFirstRep().getValue()); assertEquals("2name", p.getName().get(2).getFamilyFirstRep().getValue());
}
} }
@Test @Test
public void testSearchWithMultipleParamsOfTheSameName1() throws Exception { public void testSearchWithMultipleParamsOfTheSameName1() throws Exception {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof=po123"); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof=po123");
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent()); String responseContent = IOUtils.toString(status.getEntity().getContent());
@ -112,11 +106,9 @@ public class ReferenceParameterTest {
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("value=\"thePartOfId po123 null\"")); assertThat(responseContent, containsString("value=\"thePartOfId po123 null\""));
} }
}
@Test @Test
public void testSearchWithMultipleParamsOfTheSameName2() throws Exception { public void testSearchWithMultipleParamsOfTheSameName2() throws Exception {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof.name=poname"); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof.name=poname");
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent()); String responseContent = IOUtils.toString(status.getEntity().getContent());
@ -124,11 +116,9 @@ public class ReferenceParameterTest {
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("value=\"thePartOfName poname\"")); assertThat(responseContent, containsString("value=\"thePartOfName poname\""));
} }
}
@Test @Test
public void testSearchWithMultipleParamsOfTheSameName3() throws Exception { public void testSearchWithMultipleParamsOfTheSameName3() throws Exception {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof=po123&partof.name=poname"); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof=po123&partof.name=poname");
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent()); String responseContent = IOUtils.toString(status.getEntity().getContent());
@ -137,11 +127,9 @@ public class ReferenceParameterTest {
assertThat(responseContent, containsString("value=\"thePartOfId po123 null\"")); assertThat(responseContent, containsString("value=\"thePartOfId po123 null\""));
assertThat(responseContent, containsString("value=\"thePartOfName poname\"")); assertThat(responseContent, containsString("value=\"thePartOfName poname\""));
} }
}
@Test @Test
public void testSearchWithMultipleParamsOfTheSameName4() throws Exception { public void testSearchWithMultipleParamsOfTheSameName4() throws Exception {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof.fooChain=po123&partof.name=poname"); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof.fooChain=po123&partof.name=poname");
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent()); String responseContent = IOUtils.toString(status.getEntity().getContent());
@ -150,11 +138,9 @@ public class ReferenceParameterTest {
assertThat(responseContent, containsString("value=\"thePartOfId po123 fooChain\"")); assertThat(responseContent, containsString("value=\"thePartOfId po123 fooChain\""));
assertThat(responseContent, containsString("value=\"thePartOfName poname\"")); assertThat(responseContent, containsString("value=\"thePartOfName poname\""));
} }
}
@Test @Test
public void testSearchWithMultipleParamsOfTheSameName5() throws Exception { public void testSearchWithMultipleParamsOfTheSameName5() throws Exception {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof.bar=po123"); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof.bar=po123");
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent()); String responseContent = IOUtils.toString(status.getEntity().getContent());
@ -162,8 +148,28 @@ public class ReferenceParameterTest {
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("value=\"theBarId po123 bar\"")); 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 @Test
public void testSearchWithValueAndChain() throws Exception { public void testSearchWithValueAndChain() throws Exception {
{ {
@ -221,9 +227,7 @@ public class ReferenceParameterTest {
ServletHandler proxyHandler = new ServletHandler(); ServletHandler proxyHandler = new ServletHandler();
RestfulServer servlet = new RestfulServer(); RestfulServer servlet = new RestfulServer();
ourCtx = servlet.getFhirContext(); ourCtx = servlet.getFhirContext();
servlet.setResourceProviders(patientProvider servlet.setResourceProviders(patientProvider, new DummyOrganizationResourceProvider());
, new DummyOrganizationResourceProvider()
);
ServletHolder servletHolder = new ServletHolder(servlet); ServletHolder servletHolder = new ServletHolder(servlet);
proxyHandler.addServletWithMapping(servletHolder, "/*"); proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler); 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 //@formatter:off
@Search @Search