Allow repeatable prarmater values
This commit is contained in:
parent
ef10560c76
commit
0ba7a63803
|
@ -6,6 +6,11 @@
|
|||
<title>HAPI FHIR Changelog</title>
|
||||
</properties>
|
||||
<body>
|
||||
<release version="0.6" date="TBD">
|
||||
<action type="add">
|
||||
Allow generic client
|
||||
</action>
|
||||
</release>
|
||||
<release version="0.5" date="2014-Jul-30">
|
||||
<action type="add">
|
||||
having multiple ways of accomplishing the same thing. This means that a number of existing classes
|
||||
|
|
|
@ -74,11 +74,13 @@ import ca.uhn.fhir.rest.method.DeleteMethodBinding;
|
|||
import ca.uhn.fhir.rest.method.HistoryMethodBinding;
|
||||
import ca.uhn.fhir.rest.method.HttpDeleteClientInvocation;
|
||||
import ca.uhn.fhir.rest.method.HttpGetClientInvocation;
|
||||
import ca.uhn.fhir.rest.method.HttpPostClientInvocation;
|
||||
import ca.uhn.fhir.rest.method.HttpSimpleGetClientInvocation;
|
||||
import ca.uhn.fhir.rest.method.IClientResponseHandler;
|
||||
import ca.uhn.fhir.rest.method.MethodUtil;
|
||||
import ca.uhn.fhir.rest.method.ReadMethodBinding;
|
||||
import ca.uhn.fhir.rest.method.SearchMethodBinding;
|
||||
import ca.uhn.fhir.rest.method.SearchStyleEnum;
|
||||
import ca.uhn.fhir.rest.method.TransactionMethodBinding;
|
||||
import ca.uhn.fhir.rest.method.ValidateMethodBinding;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
|
@ -420,7 +422,8 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Bundle invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException {
|
||||
public Bundle invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException,
|
||||
BaseServerResponseException {
|
||||
EncodingEnum respType = EncodingEnum.forContentType(theResponseMimeType);
|
||||
if (respType == null) {
|
||||
throw NonFhirResponseException.newInstance(theResponseStatusCode, theResponseMimeType, theResponseReader);
|
||||
|
@ -442,7 +445,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
myResource = parseResourceBody(myResourceBody);
|
||||
}
|
||||
myId = getPreferredId(myResource, myId);
|
||||
|
||||
|
||||
BaseHttpClientInvocation invocation = MethodUtil.createCreateInvocation(myResource, myResourceBody, myId, myContext);
|
||||
|
||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(myResource);
|
||||
|
@ -455,7 +458,6 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ICreateTyped resource(IResource theResource) {
|
||||
Validate.notNull(theResource, "Resource can not be null");
|
||||
|
@ -483,7 +485,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private class UpdateInternal extends BaseClientExecutable<IUpdateTyped, MethodOutcome> implements IUpdate, IUpdateTyped {
|
||||
|
||||
private IdDt myId;
|
||||
|
@ -498,10 +500,10 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
if (myId == null) {
|
||||
myId = myResource.getId();
|
||||
}
|
||||
if (myId==null || myId.hasIdPart() == false) {
|
||||
if (myId == null || myId.hasIdPart() == false) {
|
||||
throw new InvalidRequestException("No ID supplied for resource to update, can not invoke server");
|
||||
}
|
||||
|
||||
|
||||
BaseHttpClientInvocation invocation = MethodUtil.createUpdateInvocation(myResource, myResourceBody, myId, myContext);
|
||||
|
||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(myResource);
|
||||
|
@ -533,8 +535,8 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
if (theId == null) {
|
||||
throw new NullPointerException("theId can not be null");
|
||||
}
|
||||
if (theId.hasIdPart()==false) {
|
||||
throw new NullPointerException("theId must not be blank and must contain an ID, found: "+theId.getValue());
|
||||
if (theId.hasIdPart() == false) {
|
||||
throw new NullPointerException("theId must not be blank and must contain an ID, found: " + theId.getValue());
|
||||
}
|
||||
myId = theId;
|
||||
return this;
|
||||
|
@ -546,9 +548,9 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
throw new NullPointerException("theId can not be null");
|
||||
}
|
||||
if (isBlank(theId)) {
|
||||
throw new NullPointerException("theId must not be blank and must contain an ID, found: "+theId);
|
||||
throw new NullPointerException("theId must not be blank and must contain an ID, found: " + theId);
|
||||
}
|
||||
myId=new IdDt(theId);
|
||||
myId = new IdDt(theId);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -712,7 +714,8 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
private final class OperationOutcomeResponseHandler implements IClientResponseHandler<OperationOutcome> {
|
||||
|
||||
@Override
|
||||
public OperationOutcome invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException {
|
||||
public OperationOutcome invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException,
|
||||
BaseServerResponseException {
|
||||
EncodingEnum respType = EncodingEnum.forContentType(theResponseMimeType);
|
||||
if (respType == null) {
|
||||
return null;
|
||||
|
@ -739,7 +742,8 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
}
|
||||
|
||||
@Override
|
||||
public MethodOutcome invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException {
|
||||
public MethodOutcome invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException,
|
||||
BaseServerResponseException {
|
||||
MethodOutcome response = MethodUtil.process2xxResponse(myContext, myResourceName, theResponseStatusCode, theResponseMimeType, theResponseReader, theHeaders);
|
||||
return response;
|
||||
}
|
||||
|
@ -754,7 +758,8 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<IResource> invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException {
|
||||
public List<IResource> invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException,
|
||||
BaseServerResponseException {
|
||||
return new BundleResponseHandler(myType).invokeClient(theResponseMimeType, theResponseReader, theResponseStatusCode, theHeaders).toListOfResources();
|
||||
}
|
||||
}
|
||||
|
@ -799,6 +804,8 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
private Class<? extends IResource> myResourceType;
|
||||
private List<SortInternal> mySort = new ArrayList<SortInternal>();
|
||||
|
||||
private SearchStyleEnum mySearchStyle;
|
||||
|
||||
public SearchInternal() {
|
||||
myResourceType = null;
|
||||
myResourceName = null;
|
||||
|
@ -838,7 +845,36 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
}
|
||||
|
||||
BundleResponseHandler binding = new BundleResponseHandler(myResourceType);
|
||||
HttpGetClientInvocation invocation = new HttpGetClientInvocation(params, myResourceName);
|
||||
|
||||
SearchStyleEnum searchStyle = mySearchStyle;
|
||||
if (searchStyle == null) {
|
||||
int length = 0;
|
||||
for (Entry<String, List<String>> nextEntry : params.entrySet()) {
|
||||
length += nextEntry.getKey().length();
|
||||
for (String next : nextEntry.getValue()) {
|
||||
length += next.length();
|
||||
}
|
||||
}
|
||||
|
||||
if (length < 5000) {
|
||||
searchStyle = SearchStyleEnum.GET;
|
||||
} else {
|
||||
searchStyle = SearchStyleEnum.POST;
|
||||
}
|
||||
}
|
||||
|
||||
BaseHttpClientInvocation invocation;
|
||||
switch (searchStyle) {
|
||||
case GET:
|
||||
default:
|
||||
invocation = new HttpGetClientInvocation(params, myResourceName);
|
||||
break;
|
||||
case GET_WITH_SEARCH:
|
||||
invocation = new HttpGetClientInvocation(params, myResourceName, Constants.PARAM_SEARCH);
|
||||
break;
|
||||
case POST:
|
||||
invocation = new HttpPostClientInvocation(myContext, params, myResourceName, Constants.PARAM_SEARCH);
|
||||
}
|
||||
|
||||
return invoke(params, binding, invocation);
|
||||
|
||||
|
@ -901,6 +937,12 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IQuery usingStyle(SearchStyleEnum theStyle) {
|
||||
mySearchStyle = theStyle;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class SortInternal implements ISort {
|
||||
|
@ -947,7 +989,8 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
private final class TagListResponseHandler implements IClientResponseHandler<TagList> {
|
||||
|
||||
@Override
|
||||
public TagList invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException {
|
||||
public TagList invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException,
|
||||
BaseServerResponseException {
|
||||
EncodingEnum respType = EncodingEnum.forContentType(theResponseMimeType);
|
||||
if (respType == null) {
|
||||
throw NonFhirResponseException.newInstance(theResponseStatusCode, theResponseMimeType, theResponseReader);
|
||||
|
@ -1014,5 +1057,4 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
return new UpdateInternal();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ package ca.uhn.fhir.rest.gclient;
|
|||
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.rest.method.SearchStyleEnum;
|
||||
|
||||
public interface IQuery extends IClientExecutable<IQuery,Bundle> {
|
||||
|
||||
|
@ -35,4 +36,13 @@ public interface IQuery extends IClientExecutable<IQuery,Bundle> {
|
|||
|
||||
IQuery limitTo(int theLimitTo);
|
||||
|
||||
/**
|
||||
* Forces the query to perform the search using the given method (allowable methods are described in the
|
||||
* <a href="http://www.hl7.org/implement/standards/fhir/http.html#search">FHIR Specification Section 2.1.11</a>)
|
||||
*
|
||||
* @see SearchStyleEnum
|
||||
* @since 0.6
|
||||
*/
|
||||
IQuery usingStyle(SearchStyleEnum theStyle);
|
||||
|
||||
}
|
||||
|
|
|
@ -20,6 +20,9 @@ package ca.uhn.fhir.rest.gclient;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
|
||||
|
@ -41,10 +44,8 @@ public class StringClientParam implements IParam {
|
|||
return myParamName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The string matches the given value (servers will often, but are not required to) implement this as a left match,
|
||||
* meaning that a value of "smi" would match "smi" and "smith".
|
||||
* The string matches the given value (servers will often, but are not required to) implement this as a left match, meaning that a value of "smi" would match "smi" and "smith".
|
||||
*/
|
||||
public IStringMatch matches() {
|
||||
return new StringMatches();
|
||||
|
@ -59,10 +60,28 @@ public class StringClientParam implements IParam {
|
|||
|
||||
public interface IStringMatch {
|
||||
|
||||
/**
|
||||
* Requests that resources be returned which match the given value
|
||||
*/
|
||||
ICriterion<StringClientParam> value(String theValue);
|
||||
|
||||
/**
|
||||
* Requests that resources be returned which match ANY of the given values (this is an OR search). Note that to specify an AND search, simply add a subsequent {@link IQuery#where(ICriterion)
|
||||
* where} criteria with the same parameter.
|
||||
*/
|
||||
ICriterion<StringClientParam> values(List<String> theValues);
|
||||
|
||||
/**
|
||||
* Requests that resources be returned which match the given value
|
||||
*/
|
||||
ICriterion<StringClientParam> value(StringDt theValue);
|
||||
|
||||
/**
|
||||
* Requests that resources be returned which match ANY of the given values (this is an OR search). Note that to specify an AND search, simply add a subsequent {@link IQuery#where(ICriterion)
|
||||
* where} criteria with the same parameter.
|
||||
*/
|
||||
ICriterion<?> values(String... theValues);
|
||||
|
||||
}
|
||||
|
||||
private class StringExactly implements IStringMatch {
|
||||
|
@ -75,6 +94,16 @@ public class StringClientParam implements IParam {
|
|||
public ICriterion<StringClientParam> value(StringDt theValue) {
|
||||
return new StringCriterion<StringClientParam>(getParamName() + Constants.PARAMQUALIFIER_STRING_EXACT, theValue.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICriterion<StringClientParam> values(List<String> theValue) {
|
||||
return new StringCriterion<StringClientParam>(getParamName() + Constants.PARAMQUALIFIER_STRING_EXACT, theValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICriterion<?> values(String... theValues) {
|
||||
return new StringCriterion<StringClientParam>(getParamName() + Constants.PARAMQUALIFIER_STRING_EXACT, Arrays.asList(theValues));
|
||||
}
|
||||
}
|
||||
|
||||
private class StringMatches implements IStringMatch {
|
||||
|
@ -87,6 +116,17 @@ public class StringClientParam implements IParam {
|
|||
public ICriterion<StringClientParam> value(StringDt theValue) {
|
||||
return new StringCriterion<StringClientParam>(getParamName(), theValue.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICriterion<StringClientParam> values(List<String> theValue) {
|
||||
return new StringCriterion<StringClientParam>(getParamName(), theValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICriterion<?> values(String... theValues) {
|
||||
return new StringCriterion<StringClientParam>(getParamName(), Arrays.asList(theValues));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package ca.uhn.fhir.rest.gclient;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ca.uhn.fhir.rest.param.ParameterUtil;
|
||||
|
||||
/*
|
||||
|
@ -28,8 +32,23 @@ class StringCriterion<A extends IParam> implements ICriterion<A>, ICriterionInte
|
|||
private String myName;
|
||||
|
||||
public StringCriterion(String theName, String theValue) {
|
||||
myValue = theValue;
|
||||
myName=theName;
|
||||
myValue = ParameterUtil.escape(theValue);
|
||||
}
|
||||
|
||||
public StringCriterion(String theName, List<String> theValue) {
|
||||
myName=theName;
|
||||
StringBuilder b = new StringBuilder();
|
||||
for (String next : theValue) {
|
||||
if (StringUtils.isBlank(next)) {
|
||||
continue;
|
||||
}
|
||||
if (b.length() > 0) {
|
||||
b.append(',');
|
||||
}
|
||||
b.append(ParameterUtil.escape(next));
|
||||
}
|
||||
myValue = b.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -39,7 +58,7 @@ class StringCriterion<A extends IParam> implements ICriterion<A>, ICriterionInte
|
|||
|
||||
@Override
|
||||
public String getParameterValue() {
|
||||
return ParameterUtil.escape(myValue);
|
||||
return myValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package ca.uhn.fhir.rest.gclient;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
|
||||
|
||||
/*
|
||||
|
@ -66,7 +70,17 @@ public class TokenClientParam implements IParam {
|
|||
public ICriterion<TokenClientParam> identifier(IdentifierDt theIdentifier) {
|
||||
return new TokenCriterion(getParamName(), theIdentifier.getSystem().getValueAsString(), theIdentifier.getValue().getValue());
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public ICriterion<TokenClientParam> identifiers(List<IdentifierDt> theIdentifiers) {
|
||||
return new TokenCriterion(getParamName(), theIdentifiers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICriterion<TokenClientParam> identifiers(IdentifierDt... theIdentifiers) {
|
||||
return new TokenCriterion(getParamName(), Arrays.asList(theIdentifiers));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public interface IMatches {
|
||||
|
@ -118,6 +132,27 @@ public class TokenClientParam implements IParam {
|
|||
* @return A criterion
|
||||
*/
|
||||
ICriterion<TokenClientParam> identifier(IdentifierDt theIdentifier);
|
||||
|
||||
/**
|
||||
* Creates a search criterion that matches against the given collection of identifiers (system and code if both are present, or whatever is present).
|
||||
* In the query URL that is generated, identifiers will be joined with a ',' to create an OR query.
|
||||
*
|
||||
* @param theIdentifier
|
||||
* The identifier
|
||||
* @return A criterion
|
||||
*/
|
||||
ICriterion<TokenClientParam> identifiers(List<IdentifierDt> theIdentifiers);
|
||||
|
||||
/**
|
||||
* Creates a search criterion that matches against the given collection of identifiers (system and code if both are present, or whatever is present).
|
||||
* In the query URL that is generated, identifiers will be joined with a ',' to create an OR query.
|
||||
*
|
||||
* @param theIdentifier
|
||||
* The identifier
|
||||
* @return A criterion
|
||||
*/
|
||||
ICriterion<TokenClientParam> identifiers(IdentifierDt... theIdentifiers);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,8 +20,11 @@ package ca.uhn.fhir.rest.gclient;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
|
||||
import ca.uhn.fhir.rest.param.ParameterUtil;
|
||||
|
||||
class TokenCriterion implements ICriterion<TokenClientParam>, ICriterionInternal {
|
||||
|
@ -31,15 +34,36 @@ class TokenCriterion implements ICriterion<TokenClientParam>, ICriterionInternal
|
|||
|
||||
public TokenCriterion(String theName, String theSystem, String theCode) {
|
||||
myName = theName;
|
||||
myValue=toValue(theSystem, theCode);
|
||||
}
|
||||
|
||||
private String toValue(String theSystem, String theCode) {
|
||||
String system = ParameterUtil.escape(theSystem);
|
||||
String code = ParameterUtil.escape(theCode);
|
||||
String value;
|
||||
if (StringUtils.isNotBlank(system)) {
|
||||
myValue = system + "|" + StringUtils.defaultString(code);
|
||||
value = system + "|" + StringUtils.defaultString(code);
|
||||
} else if (system == null) {
|
||||
myValue = StringUtils.defaultString(code);
|
||||
value = StringUtils.defaultString(code);
|
||||
} else {
|
||||
myValue = "|" + StringUtils.defaultString(code);
|
||||
value = "|" + StringUtils.defaultString(code);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public TokenCriterion(String theParamName, List<IdentifierDt> theValue) {
|
||||
myName=theParamName;
|
||||
StringBuilder b = new StringBuilder();
|
||||
for (IdentifierDt next : theValue) {
|
||||
if (next.getSystem().isEmpty() && next.getValue().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (b.length() > 0) {
|
||||
b.append(',');
|
||||
}
|
||||
b.append(toValue(next.getSystem().getValueAsString(), next.getValue().getValue()));
|
||||
}
|
||||
myValue = b.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -22,15 +22,21 @@ package ca.uhn.fhir.rest.method;
|
|||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.apache.http.entity.AbstractHttpEntity;
|
||||
import org.apache.http.entity.ByteArrayEntity;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
|
@ -42,6 +48,7 @@ import ca.uhn.fhir.parser.IParser;
|
|||
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
|
||||
abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvocation {
|
||||
|
||||
|
@ -53,6 +60,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
|
|||
private final Bundle myBundle;
|
||||
private final String myContents;
|
||||
private boolean myContentsIsBundle;
|
||||
private Map<String, List<String>> myParams;
|
||||
|
||||
public BaseHttpClientInvocationWithContents(FhirContext theContext, IResource theResource, String theUrlExtension) {
|
||||
super();
|
||||
|
@ -112,6 +120,18 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
|
|||
myContentsIsBundle = theIsBundle;
|
||||
}
|
||||
|
||||
public BaseHttpClientInvocationWithContents(FhirContext theContext, Map<String, List<String>> theParams, String... theUrlExtension) {
|
||||
myContext = theContext;
|
||||
myResource = null;
|
||||
myTagList = null;
|
||||
myUrlExtension = StringUtils.join(theUrlExtension, '/');
|
||||
myResources = null;
|
||||
myBundle = null;
|
||||
myContents = null;
|
||||
myContentsIsBundle = false;
|
||||
myParams = theParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpRequestBase asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding) throws DataFormatException {
|
||||
StringBuilder b = new StringBuilder();
|
||||
|
@ -145,31 +165,43 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
|
|||
parser = myContext.newXmlParser();
|
||||
}
|
||||
|
||||
String contents;
|
||||
if (myTagList != null) {
|
||||
contents = parser.encodeTagListToString(myTagList);
|
||||
contentType = encoding.getResourceContentType();
|
||||
} else if (myBundle != null) {
|
||||
contents = parser.encodeBundleToString(myBundle);
|
||||
contentType = encoding.getBundleContentType();
|
||||
} else if (myResources != null) {
|
||||
Bundle bundle = RestfulServer.createBundleFromResourceList(myContext, "", myResources, "", "", myResources.size());
|
||||
contents = parser.encodeBundleToString(bundle);
|
||||
contentType = encoding.getBundleContentType();
|
||||
} else if (myContents != null) {
|
||||
contents = myContents;
|
||||
if (myContentsIsBundle) {
|
||||
contentType = encoding.getBundleContentType();
|
||||
} else {
|
||||
contentType = encoding.getResourceContentType();
|
||||
AbstractHttpEntity entity;
|
||||
if (myParams != null) {
|
||||
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
|
||||
for (Entry<String, List<String>> nextParam : myParams.entrySet()) {
|
||||
parameters.add(new BasicNameValuePair(nextParam.getKey(), StringUtils.join(nextParam.getValue(), ',')));
|
||||
}
|
||||
try {
|
||||
entity = new UrlEncodedFormEntity(parameters, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new InternalErrorException("Server does not support UTF-8 (should not happen)", e);
|
||||
}
|
||||
} else {
|
||||
contents = parser.encodeResourceToString(myResource);
|
||||
contentType = encoding.getResourceContentType();
|
||||
String contents;
|
||||
if (myTagList != null) {
|
||||
contents = parser.encodeTagListToString(myTagList);
|
||||
contentType = encoding.getResourceContentType();
|
||||
} else if (myBundle != null) {
|
||||
contents = parser.encodeBundleToString(myBundle);
|
||||
contentType = encoding.getBundleContentType();
|
||||
} else if (myResources != null) {
|
||||
Bundle bundle = RestfulServer.createBundleFromResourceList(myContext, "", myResources, "", "", myResources.size());
|
||||
contents = parser.encodeBundleToString(bundle);
|
||||
contentType = encoding.getBundleContentType();
|
||||
} else if (myContents != null) {
|
||||
contents = myContents;
|
||||
if (myContentsIsBundle) {
|
||||
contentType = encoding.getBundleContentType();
|
||||
} else {
|
||||
contentType = encoding.getResourceContentType();
|
||||
}
|
||||
} else {
|
||||
contents = parser.encodeResourceToString(myResource);
|
||||
contentType = encoding.getResourceContentType();
|
||||
}
|
||||
entity = new StringEntity(contents, ContentType.create(contentType, "UTF-8"));
|
||||
}
|
||||
|
||||
StringEntity entity = new StringEntity(contents, ContentType.create(contentType, "UTF-8"));
|
||||
|
||||
HttpRequestBase retVal = createRequest(url, entity);
|
||||
super.addHeadersToRequest(retVal);
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ package ca.uhn.fhir.rest.method;
|
|||
*/
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.AbstractHttpEntity;
|
||||
|
@ -56,6 +57,11 @@ public class HttpPostClientInvocation extends BaseHttpClientInvocationWithConten
|
|||
}
|
||||
|
||||
|
||||
public HttpPostClientInvocation(FhirContext theContext, Map<String, List<String>> theParams, String... theUrlExtension) {
|
||||
super(theContext, theParams, theUrlExtension);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected HttpPost createRequest(String url, AbstractHttpEntity theEntity) {
|
||||
HttpPost retVal = new HttpPost(url);
|
||||
|
|
|
@ -31,6 +31,6 @@ interface IParamBinder {
|
|||
|
||||
List<IQueryParameterOr<?>> encode(FhirContext theContext, Object theString) throws InternalErrorException;
|
||||
|
||||
Object parse(List<QualifiedParamList> theList) throws InternalErrorException, InvalidRequestException;
|
||||
Object parse(String theName, List<QualifiedParamList> theList) throws InternalErrorException, InvalidRequestException;
|
||||
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ final class QueryParameterAndBinder extends BaseBinder<IQueryParameterAnd<?>> im
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object parse(List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException {
|
||||
public Object parse(String theName, List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException {
|
||||
IQueryParameterAnd<?> dt;
|
||||
try {
|
||||
dt = newInstance();
|
||||
|
|
|
@ -44,7 +44,7 @@ final class QueryParameterOrBinder extends BaseBinder<IQueryParameterOr<?>> impl
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object parse(List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException {
|
||||
public Object parse(String theName, List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException {
|
||||
IQueryParameterOr<?> dt;
|
||||
try {
|
||||
dt = newInstance();
|
||||
|
@ -52,7 +52,7 @@ final class QueryParameterOrBinder extends BaseBinder<IQueryParameterOr<?>> impl
|
|||
return dt;
|
||||
}
|
||||
if (theString.size() > 1) {
|
||||
throw new InvalidRequestException("Multiple values detected");
|
||||
throw new InvalidRequestException("Multiple values detected for non-repeatable parameter '" + theName + "'. This server is not configured to allow multiple (AND/OR) values for this param.");
|
||||
}
|
||||
|
||||
dt.setValuesAsQueryTokens(theString.get(0));
|
||||
|
|
|
@ -46,7 +46,7 @@ final class QueryParameterTypeBinder extends BaseBinder<IQueryParameterType> imp
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object parse(List<QualifiedParamList> theParams) throws InternalErrorException, InvalidRequestException {
|
||||
public Object parse(String theName, List<QualifiedParamList> theParams) throws InternalErrorException, InvalidRequestException {
|
||||
String value = theParams.get(0).get(0);
|
||||
if (StringUtils.isBlank(value)) {
|
||||
return null;
|
||||
|
@ -58,7 +58,7 @@ final class QueryParameterTypeBinder extends BaseBinder<IQueryParameterType> imp
|
|||
return dt;
|
||||
}
|
||||
if (theParams.size() > 1 || theParams.get(0).size() > 1) {
|
||||
throw new InvalidRequestException("Multiple values detected");
|
||||
throw new InvalidRequestException("Multiple values detected for non-repeatable parameter '" + theName + "'. This server is not configured to allow multiple (AND/OR) values for this param.");
|
||||
}
|
||||
|
||||
dt.setValueAsQueryToken(theParams.get(0).getQualifier(), value);
|
||||
|
|
|
@ -184,7 +184,7 @@ public class SearchParameter extends BaseQueryParameter {
|
|||
*/
|
||||
@Override
|
||||
public Object parse(List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException {
|
||||
return myParamBinder.parse(theString);
|
||||
return myParamBinder.parse(getName(), theString);
|
||||
}
|
||||
|
||||
public void setCompositeTypes(Class<? extends IQueryParameterType>[] theCompositeTypes) {
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package ca.uhn.fhir.rest.method;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 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%
|
||||
*/
|
||||
|
||||
/**
|
||||
* Enumerated type to represent the various allowable syntax for a search/query
|
||||
* as described in the
|
||||
* <a href="http://www.hl7.org/implement/standards/fhir/http.html#search">FHIR Specification Section 2.1.11</a>
|
||||
*/
|
||||
public enum SearchStyleEnum {
|
||||
|
||||
/**
|
||||
* This is the most common (and generally the default) behaviour. Performs the search using the style:
|
||||
* <br/>
|
||||
* <code>GET [base]/[resource type]?[params]</code>
|
||||
*/
|
||||
GET,
|
||||
|
||||
/**
|
||||
* This is the most common (and generally the default) behaviour. Performs the search using the style:
|
||||
* <br/>
|
||||
* <code>GET [base]/[resource type]/_search?[params]</code>
|
||||
*/
|
||||
GET_WITH_SEARCH,
|
||||
|
||||
/**
|
||||
* This is the most common (and generally the default) behaviour. Performs the search using the style:
|
||||
* <br/>
|
||||
* <code>POST [base]/[resource type]/_search</code>
|
||||
* <br/>
|
||||
* and the params in a form encoded POST body.
|
||||
*/
|
||||
POST
|
||||
|
||||
}
|
|
@ -42,12 +42,12 @@ final class StringBinder implements IParamBinder {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object parse(List<QualifiedParamList> theParams) throws InternalErrorException, InvalidRequestException {
|
||||
public Object parse(String theName, List<QualifiedParamList> theParams) throws InternalErrorException, InvalidRequestException {
|
||||
if (theParams.size() == 0 || theParams.get(0).size() == 0) {
|
||||
return "";
|
||||
}
|
||||
if (theParams.size() > 1 || theParams.get(0).size() > 1) {
|
||||
throw new InvalidRequestException("Multiple values detected");
|
||||
throw new InvalidRequestException("Multiple values detected for non-repeatable parameter '" + theName + "'. This server is not configured to allow multiple (AND) values for this param.");
|
||||
}
|
||||
|
||||
return theParams.get(0).get(0);
|
||||
|
|
|
@ -149,7 +149,7 @@ public class RestfulServer extends HttpServlet {
|
|||
|
||||
private void assertProviderIsValid(Object theNext) throws ConfigurationException {
|
||||
if (Modifier.isPublic(theNext.getClass().getModifiers()) == false) {
|
||||
throw new ConfigurationException("Can not use provider '" + theNext.getClass() + "' - Must be public");
|
||||
throw new ConfigurationException("Can not use provider '" + theNext.getClass() + "' - Class ust be public");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import ca.uhn.fhir.model.dstu.resource.Organization;
|
|||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.client.IGenericClient;
|
||||
import ca.uhn.fhir.rest.method.SearchStyleEnum;
|
||||
|
||||
public class GenericClientExample {
|
||||
|
||||
|
@ -100,10 +101,25 @@ Bundle response = client.search()
|
|||
.forResource(Patient.class)
|
||||
.where(Patient.BIRTHDATE.beforeOrEquals().day("2011-01-01"))
|
||||
.and(Patient.PROVIDER.hasChainedProperty(Organization.NAME.matches().value("Health")))
|
||||
.andLogRequestAndResponse(true)
|
||||
.execute();
|
||||
//END SNIPPET: search
|
||||
|
||||
//START SNIPPET: searchOr
|
||||
response = client.search()
|
||||
.forResource(Patient.class)
|
||||
.where(Patient.FAMILY.matches().values("Smith", "Smyth"))
|
||||
.execute();
|
||||
//END SNIPPET: searchOr
|
||||
|
||||
//START SNIPPET: searchAnd
|
||||
response = client.search()
|
||||
.forResource(Patient.class)
|
||||
.where(Patient.ADDRESS.matches().values("Toronto"))
|
||||
.where(Patient.ADDRESS.matches().values("Ontario"))
|
||||
.where(Patient.ADDRESS.matches().values("Canada"))
|
||||
.execute();
|
||||
//END SNIPPET: searchAnd
|
||||
|
||||
//START SNIPPET: searchAdv
|
||||
response = client.search()
|
||||
.forResource(Patient.class)
|
||||
|
@ -117,6 +133,15 @@ response = client.search()
|
|||
.execute();
|
||||
//END SNIPPET: searchAdv
|
||||
|
||||
//START SNIPPET: searchPost
|
||||
response = client.search()
|
||||
.forResource("Patient")
|
||||
.where(Patient.NAME.matches().value("Tester"))
|
||||
.usingStyle(SearchStyleEnum.POST)
|
||||
.execute();
|
||||
//END SNIPPET: searchPost
|
||||
|
||||
|
||||
//START SNIPPET: searchComposite
|
||||
response = client.search()
|
||||
.forResource("Observation")
|
||||
|
|
|
@ -99,6 +99,30 @@
|
|||
value="src/site/example/java/example/GenericClientExample.java" />
|
||||
</macro>
|
||||
|
||||
<h4>Search - Multi-valued Parameters (ANY/OR)</h4>
|
||||
<p>
|
||||
To search for a set of possible values where <b>ANY</b> should be matched,
|
||||
you can provide multiple values to a parameter, as shown in the example below.
|
||||
This leads to a URL resembling <code>?family=Smith,Smyth</code>
|
||||
</p>
|
||||
<macro name="snippet">
|
||||
<param name="id" value="searchOr" />
|
||||
<param name="file"
|
||||
value="src/site/example/java/example/GenericClientExample.java" />
|
||||
</macro>
|
||||
|
||||
<h4>Search - Multi-valued Parameters (ALL/AND)</h4>
|
||||
<p>
|
||||
To search for a set of possible values where <b>ALL</b> should be matched,
|
||||
you can provide multiple instances of a marameter, as shown in the example below.
|
||||
This leads to a URL resembling <code>?address=Toronto&address=Ontario&address=Canada</code>
|
||||
</p>
|
||||
<macro name="snippet">
|
||||
<param name="id" value="searchOr" />
|
||||
<param name="file"
|
||||
value="src/site/example/java/example/GenericClientExample.java" />
|
||||
</macro>
|
||||
|
||||
<h4>Search - Paging</h4>
|
||||
<p>
|
||||
If the server supports paging results, the client has a page method
|
||||
|
@ -123,7 +147,7 @@
|
|||
value="src/site/example/java/example/GenericClientExample.java" />
|
||||
</macro>
|
||||
|
||||
<h4>Search - Query Options</h4>
|
||||
<h4>Search - Other Query Options</h4>
|
||||
<p>
|
||||
The fluent search also has methods for sorting, limiting, specifying
|
||||
JSON encoding, etc.
|
||||
|
@ -133,6 +157,19 @@
|
|||
<param name="file"
|
||||
value="src/site/example/java/example/GenericClientExample.java" />
|
||||
</macro>
|
||||
|
||||
<h4>Search - Using HTTP POST or GET with _search</h4>
|
||||
<p>
|
||||
The FHIR specification allows several styles of search (HTTP POST, a GET with _search at the end of the URL, etc.)
|
||||
The <code>usingStyle()</code> method controls which style to use. By default, GET style is used
|
||||
unless the client detects that the request would result in a very long URL (over 8000 chars) in which
|
||||
case the client automatically switches to POST.
|
||||
</p>
|
||||
<macro name="snippet">
|
||||
<param name="id" value="searchPost" />
|
||||
<param name="file"
|
||||
value="src/site/example/java/example/GenericClientExample.java" />
|
||||
</macro>
|
||||
|
||||
</subsection>
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -8,10 +8,14 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
|
@ -22,11 +26,16 @@ import org.junit.Test;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu.composite.CodingDt;
|
||||
import ca.uhn.fhir.model.dstu.resource.Observation;
|
||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
||||
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.param.TokenOrListParam;
|
||||
import ca.uhn.fhir.testutil.RandomServerPortProvider;
|
||||
|
||||
/**
|
||||
|
@ -35,24 +44,9 @@ import ca.uhn.fhir.testutil.RandomServerPortProvider;
|
|||
public class SearchTest {
|
||||
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static FhirContext ourCtx = new FhirContext();
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private static FhirContext ourCtx = new FhirContext();
|
||||
|
||||
@Test
|
||||
public void testSearchById() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_id=aaa");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
|
||||
assertEquals(1, bundle.getEntries().size());
|
||||
|
||||
Patient p = bundle.getResources(Patient.class).get(0);
|
||||
assertEquals("idaaa", p.getNameFirstRep().getFamilyAsSingleString());
|
||||
assertEquals("IDAAA (identifier123)", bundle.getEntries().get(0).getTitle().getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOmitEmptyOptionalParam() throws Exception {
|
||||
|
@ -63,13 +57,69 @@ public class SearchTest {
|
|||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
|
||||
assertEquals(1, bundle.getEntries().size());
|
||||
|
||||
|
||||
Patient p = bundle.getResources(Patient.class).get(0);
|
||||
assertEquals(null, p.getNameFirstRep().getFamilyFirstRep().getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchById() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_id=aaa");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
|
||||
assertEquals(1, bundle.getEntries().size());
|
||||
|
||||
Patient p = bundle.getResources(Patient.class).get(0);
|
||||
assertEquals("idaaa", p.getNameFirstRep().getFamilyAsSingleString());
|
||||
assertEquals("IDAAA (identifier123)", bundle.getEntries().get(0).getTitle().getValue());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchByPost() throws Exception {
|
||||
HttpPost filePost = new HttpPost("http://localhost:" + ourPort + "/Patient/_search");
|
||||
|
||||
// add parameters to the post method
|
||||
List <NameValuePair> parameters = new ArrayList <NameValuePair>();
|
||||
parameters.add(new BasicNameValuePair("_id", "aaa"));
|
||||
|
||||
UrlEncodedFormEntity sendentity = new UrlEncodedFormEntity(parameters, "UTF-8");
|
||||
filePost.setEntity(sendentity);
|
||||
|
||||
HttpResponse status = ourClient.execute(filePost);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
|
||||
assertEquals(1, bundle.getEntries().size());
|
||||
|
||||
Patient p = bundle.getResources(Patient.class).get(0);
|
||||
assertEquals("idaaa", p.getNameFirstRep().getFamilyAsSingleString());
|
||||
assertEquals("IDAAA (identifier123)", bundle.getEntries().get(0).getTitle().getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchGetWithUnderscoreSearch() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort+"/Observation/_search?subject%3APatient=100&name=3141-9%2C8302-2%2C8287-5%2C39156-5");
|
||||
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
|
||||
assertEquals(1, bundle.getEntries().size());
|
||||
|
||||
Observation p = bundle.getResources(Observation.class).get(0);
|
||||
assertEquals("Patient/100", p.getSubject().getReference().toString());
|
||||
assertEquals(4, p.getName().getCoding().size());
|
||||
assertEquals("3141-9", p.getName().getCoding().get(0).getCode().getValue());
|
||||
assertEquals("8302-2", p.getName().getCoding().get(1).getCode().getValue());
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
ourServer.stop();
|
||||
|
@ -85,8 +135,8 @@ public class SearchTest {
|
|||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer();
|
||||
servlet.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
||||
|
||||
servlet.setResourceProviders(patientProvider);
|
||||
|
||||
servlet.setResourceProviders(patientProvider, new DummyObservationResourceProvider());
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
|
@ -99,6 +149,28 @@ public class SearchTest {
|
|||
|
||||
}
|
||||
|
||||
public static class DummyObservationResourceProvider implements IResourceProvider{
|
||||
|
||||
@Override
|
||||
public Class<? extends IResource> getResourceType() {
|
||||
return Observation.class;
|
||||
}
|
||||
|
||||
@Search
|
||||
public Observation search(@RequiredParam(name="subject") ReferenceParam theSubject, @RequiredParam(name="name") TokenOrListParam theName) {
|
||||
Observation o = new Observation();
|
||||
o.setId("1");
|
||||
|
||||
o.getSubject().setReference(theSubject.getResourceType() + "/" + theSubject.getIdPart());
|
||||
for (CodingDt next : theName.getListAsCodings()) {
|
||||
o.getName().getCoding().add(next);
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
*/
|
||||
|
@ -111,8 +183,8 @@ public class SearchTest {
|
|||
Patient patient = new Patient();
|
||||
patient.setId("1");
|
||||
patient.addIdentifier("system", "identifier123");
|
||||
if (theParam!=null) {
|
||||
patient.addName().addFamily("id"+theParam.getValue());
|
||||
if (theParam != null) {
|
||||
patient.addName().addFamily("id" + theParam.getValue());
|
||||
}
|
||||
retVal.add(patient);
|
||||
return retVal;
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hamcrest.core.StringContains;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@ -19,7 +23,12 @@ import ca.uhn.fhir.model.primitive.StringDt;
|
|||
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.annotation.ServerBase;
|
||||
import ca.uhn.fhir.rest.client.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.IBasicClient;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.rest.gclient.StringClientParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.testutil.RandomServerPortProvider;
|
||||
|
||||
public class ServerExtraParametersTest {
|
||||
|
@ -58,6 +67,28 @@ public class ServerExtraParametersTest {
|
|||
assertEquals("http://localhost:" + myPort, patientProvider.getServerBase());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonRepeatableParam() throws Exception {
|
||||
MyServerBaseProvider patientProvider = new MyServerBaseProvider();
|
||||
myServlet.setResourceProviders(patientProvider);
|
||||
|
||||
myServer.start();
|
||||
|
||||
FhirContext ctx = new FhirContext();
|
||||
IGenericClient client = ctx.newRestfulGenericClient("http://localhost:" + myPort + "/");
|
||||
client.registerInterceptor(new LoggingInterceptor(true));
|
||||
|
||||
try {
|
||||
client.search().forResource("Patient").where(new StringClientParam("singleParam").matches().values(Arrays.asList("AA", "BB"))).execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertThat(
|
||||
e.getMessage(),
|
||||
StringContains
|
||||
.containsString("HTTP 400 Bad Request: Multiple values detected for non-repeatable parameter 'singleParam'. This server is not configured to allow multiple (AND/OR) values for this param."));
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() throws Exception {
|
||||
myServer.stop();
|
||||
|
@ -75,6 +106,13 @@ public class ServerExtraParametersTest {
|
|||
return Patient.class;
|
||||
}
|
||||
|
||||
@Search
|
||||
public List<Patient> searchSingleParam(@RequiredParam(name = "singleParam") StringParam theFooParam) {
|
||||
Patient retVal = new Patient();
|
||||
retVal.setId("1");
|
||||
return Collections.singletonList(retVal);
|
||||
}
|
||||
|
||||
@Search
|
||||
public List<Patient> searchForPatients(@RequiredParam(name = "fooParam") StringDt theFooParam, @ServerBase String theServerBase) {
|
||||
myServerBase = theServerBase;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<wb-resource deploy-path="/" source-path="/target/m2e-wtp/web-resources"/>
|
||||
<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
|
||||
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
|
||||
<dependent-module archiveName="hapi-fhir-base-0.5.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/hapi-fhir-base/hapi-fhir-base">
|
||||
<dependent-module archiveName="hapi-fhir-base-0.6-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/hapi-fhir-base/hapi-fhir-base">
|
||||
<dependency-type>uses</dependency-type>
|
||||
</dependent-module>
|
||||
<dependent-module deploy-path="/" handle="module:/overlay/prj/hapi-fhir-testpage-overlay?includes=**/**&excludes=META-INF/MANIFEST.MF">
|
||||
|
|
Loading…
Reference in New Issue