Merge branch 'master' of github.com:jamesagnew/hapi-fhir

This commit is contained in:
James 2016-10-06 06:28:06 -04:00
commit a4975887b8
48 changed files with 459 additions and 267 deletions

View File

@ -22,6 +22,7 @@ package ca.uhn.fhir.model.api;
import java.util.List;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.method.QualifiedParamList;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
@ -34,8 +35,10 @@ public interface IQueryParameterAnd<T extends IQueryParameterOr<?>> {
* <a href="http://www.hl7.org/implement/standards/fhir/search.html#ptypes">2.2.2 Search SearchParameter Types</a>
* for information on the <b>token</b> format
* </p>
* @param theContext TODO
* @param theParamName TODO
*/
public void setValuesAsQueryTokens(List<QualifiedParamList> theParameters) throws InvalidRequestException;
public void setValuesAsQueryTokens(FhirContext theContext, String theParamName, List<QualifiedParamList> theParameters) throws InvalidRequestException;
/**
*

View File

@ -22,11 +22,12 @@ package ca.uhn.fhir.model.api;
import java.util.List;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.method.QualifiedParamList;
public interface IQueryParameterOr<T extends IQueryParameterType> {
public void setValuesAsQueryTokens(QualifiedParamList theParameters);
public void setValuesAsQueryTokens(FhirContext theContext, String theParamName, QualifiedParamList theParameters);
public List<T> getValuesAsQueryTokens();

View File

@ -31,7 +31,8 @@ public interface IQueryParameterType {
* See FHIR specification <a href="http://www.hl7.org/implement/standards/fhir/search.html#ptypes">2.2.2 Search
* SearchParameter Types</a> for information on the <b>token</b> format
* </p>
*
* @param theContext TODO
* @param theParamName TODO
* @param theQualifier
* The parameter name qualifier that accompanied this value. For example, if the complete query was
* <code>http://foo?name:exact=John</code>, qualifier would be ":exact"
@ -39,7 +40,7 @@ public interface IQueryParameterType {
* The actual parameter value. For example, if the complete query was
* <code>http://foo?name:exact=John</code>, the value would be "John"
*/
public void setValueAsQueryToken(String theQualifier, String theValue);
public void setValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue);
/**
* Returns a representation of this parameter's value as it will be represented "over the wire". In other

View File

@ -94,7 +94,7 @@ public abstract class BaseCodingDt extends BaseIdentifiableElement implements IC
* {@inheritDoc}
*/
@Override
public void setValueAsQueryToken(String theQualifier, String theParameter) {
public void setValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theParameter) {
int barIndex = ParameterUtil.nonEscapedIndexOf(theParameter, '|');
if (barIndex != -1) {
setSystem(theParameter.substring(0, barIndex));

View File

@ -104,7 +104,7 @@ public abstract class BaseIdentifierDt extends BaseIdentifiableElement implement
* {@inheritDoc}
*/
@Override
public void setValueAsQueryToken(String theQualifier, String theParameter) {
public void setValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theParameter) {
int barIndex = ParameterUtil.nonEscapedIndexOf(theParameter, '|');
if (barIndex != -1) {
setSystem(theParameter.substring(0, barIndex));

View File

@ -51,7 +51,7 @@ public abstract class BaseQuantityDt extends BaseIdentifiableElement implements
@Override
public void setValueAsQueryToken(String theQualifier, String theValue) {
public void setValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) {
getComparatorElement().setValue(null);
setCode( null);
setSystem(null);

View File

@ -88,7 +88,7 @@ public class StringDt extends BasePrimitive<String> implements IQueryParameterTy
* {@inheritDoc}
*/
@Override
public void setValueAsQueryToken(String theQualifier, String theValue) {
public void setValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) {
setValue(theValue);
}

View File

@ -48,12 +48,12 @@ abstract class BaseJavaPrimitiveBinder<T>implements IParamBinder<T> {
if (isBlank(retVal)) {
return Collections.emptyList();
}
List<?> retValList = Collections.singletonList(MethodUtil.singleton(new StringParam(retVal)));
List<?> retValList = Collections.singletonList(MethodUtil.singleton(new StringParam(retVal), null));
return (List<IQueryParameterOr<?>>) retValList;
}
@Override
public T parse(String theName, List<QualifiedParamList> theParams) throws InternalErrorException, InvalidRequestException {
public T parse(FhirContext theContext, String theName, List<QualifiedParamList> theParams) throws InternalErrorException, InvalidRequestException {
if (theParams.size() == 0 || theParams.get(0).size() == 0) {
return null;
}

View File

@ -73,6 +73,7 @@ public class DynamicSearchParameter implements IParameter {
for (String next : theRequest.getParameters().keySet()) {
String qualifier = null;
String qualifiedParamName = next;
String unqualifiedParamName = next;
RuntimeSearchParam param = myNameToParam.get(next);
if (param == null) {
int colonIndex = next.indexOf(':');
@ -86,6 +87,7 @@ public class DynamicSearchParameter implements IParameter {
}
qualifier = next.substring(index);
next = next.substring(0, index);
unqualifiedParamName = next;
param = myNameToParam.get(next);
}
}
@ -95,48 +97,50 @@ public class DynamicSearchParameter implements IParameter {
for (String nextValue : theRequest.getParameters().get(qualifiedParamName)) {
QualifiedParamList paramList = QualifiedParamList.splitQueryStringByCommasIgnoreEscape(qualifier, nextValue);
FhirContext ctx = theRequest.getServer().getFhirContext();
switch (param.getParamType()) {
case COMPOSITE:
Class<? extends IQueryParameterType> left = toParamType(param.getCompositeOf().get(0));
Class<? extends IQueryParameterType> right = toParamType(param.getCompositeOf().get(0));
@SuppressWarnings({ "rawtypes" })
CompositeOrListParam compositeOrListParam = new CompositeOrListParam(left, right);
compositeOrListParam.setValuesAsQueryTokens(paramList);
compositeOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList);
retVal.add(next, compositeOrListParam);
break;
case DATE:
DateOrListParam dateOrListParam = new DateOrListParam();
dateOrListParam.setValuesAsQueryTokens(paramList);
dateOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList);
retVal.add(next, dateOrListParam);
break;
case NUMBER:
NumberOrListParam numberOrListParam = new NumberOrListParam();
numberOrListParam.setValuesAsQueryTokens(paramList);
numberOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList);
retVal.add(next, numberOrListParam);
break;
case QUANTITY:
QuantityOrListParam quantityOrListParam = new QuantityOrListParam();
quantityOrListParam.setValuesAsQueryTokens(paramList);
quantityOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList);
retVal.add(next, quantityOrListParam);
break;
case REFERENCE:
ReferenceOrListParam referenceOrListParam = new ReferenceOrListParam();
referenceOrListParam.setValuesAsQueryTokens(paramList);
referenceOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList);
retVal.add(next, referenceOrListParam);
break;
case STRING:
StringOrListParam stringOrListParam = new StringOrListParam();
stringOrListParam.setValuesAsQueryTokens(paramList);
stringOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList);
retVal.add(next, stringOrListParam);
break;
case TOKEN:
TokenOrListParam tokenOrListParam = new TokenOrListParam();
tokenOrListParam.setValuesAsQueryTokens(paramList);
tokenOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList);
retVal.add(next, tokenOrListParam);
break;
case URI:
UriOrListParam uriOrListParam = new UriOrListParam();
uriOrListParam.setValuesAsQueryTokens(paramList);
uriOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList);
retVal.add(next, uriOrListParam);
break;
}

View File

@ -31,6 +31,6 @@ interface IParamBinder<T> {
List<IQueryParameterOr<?>> encode(FhirContext theContext, T theString) throws InternalErrorException;
T parse(String theName, List<QualifiedParamList> theList) throws InternalErrorException, InvalidRequestException;
T parse(FhirContext theContext, String theName, List<QualifiedParamList> theList) throws InternalErrorException, InvalidRequestException;
}

View File

@ -608,16 +608,16 @@ public class MethodUtil {
/**
* This is a utility method intended provided to help the JPA module.
*/
public static IQueryParameterAnd<?> parseQueryParams(RuntimeSearchParam theParamDef, String theUnqualifiedParamName, List<QualifiedParamList> theParameters) {
public static IQueryParameterAnd<?> parseQueryParams(FhirContext theContext, RuntimeSearchParam theParamDef, String theUnqualifiedParamName, List<QualifiedParamList> theParameters) {
RestSearchParameterTypeEnum paramType = theParamDef.getParamType();
return parseQueryParams(paramType, theUnqualifiedParamName, theParameters);
return parseQueryParams(theContext, paramType, theUnqualifiedParamName, theParameters);
}
/**
* This is a utility method intended provided to help the JPA module.
*/
public static IQueryParameterAnd<?> parseQueryParams(RestSearchParameterTypeEnum paramType, String theUnqualifiedParamName, List<QualifiedParamList> theParameters) {
public static IQueryParameterAnd<?> parseQueryParams(FhirContext theContext, RestSearchParameterTypeEnum paramType, String theUnqualifiedParamName, List<QualifiedParamList> theParameters) {
QueryParameterAndBinder binder = null;
switch (paramType) {
case COMPOSITE:
@ -648,7 +648,7 @@ public class MethodUtil {
break;
}
return binder.parse(theUnqualifiedParamName, theParameters);
return binder.parse(theContext, theUnqualifiedParamName, theParameters);
}
public static void parseTagValue(TagList tagList, String nextTagComplete) {
@ -779,7 +779,7 @@ public class MethodUtil {
return retVal;
}
public static IQueryParameterOr<?> singleton(final IQueryParameterType theParam) {
public static IQueryParameterOr<?> singleton(final IQueryParameterType theParam, final String theParamName) {
return new IQueryParameterOr<IQueryParameterType>() {
@Override
@ -788,14 +788,14 @@ public class MethodUtil {
}
@Override
public void setValuesAsQueryTokens(QualifiedParamList theParameters) {
public void setValuesAsQueryTokens(FhirContext theContext, String theParamName, QualifiedParamList theParameters) {
if (theParameters.isEmpty()) {
return;
}
if (theParameters.size() > 1) {
throw new IllegalArgumentException("Type " + theParam.getClass().getCanonicalName() + " does not support multiple values");
}
theParam.setValueAsQueryToken(theParameters.getQualifier(), theParameters.get(0));
theParam.setValueAsQueryToken(theContext, theParamName, theParameters.getQualifier(), theParameters.get(0));
}
};
}

View File

@ -304,7 +304,8 @@ public class OperationParameter implements IParameter {
parameters.add(QualifiedParamList.singleton(paramValues[1]));
}
DateRangeParam dateRangeParam = new DateRangeParam();
dateRangeParam.setValuesAsQueryTokens(parameters);
FhirContext ctx = theRequest.getServer().getFhirContext();
dateRangeParam.setValuesAsQueryTokens(ctx, myName, parameters);
matchingParamValues.add(dateRangeParam);
} else if (String.class.isAssignableFrom(myParameterType)) {

View File

@ -43,11 +43,11 @@ final class QueryParameterAndBinder extends BaseBinder<IQueryParameterAnd<?>> im
}
@Override
public IQueryParameterAnd<?> parse(String theName, List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException {
public IQueryParameterAnd<?> parse(FhirContext theContext, String theParamName, List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException {
IQueryParameterAnd<?> dt;
try {
dt = newInstance();
dt.setValuesAsQueryTokens(theString);
dt.setValuesAsQueryTokens(theContext, theParamName, theString);
} catch (SecurityException e) {
throw new InternalErrorException(e);
}

View File

@ -44,7 +44,7 @@ final class QueryParameterOrBinder extends BaseBinder<IQueryParameterOr<?>> impl
}
@Override
public IQueryParameterOr<?> parse(String theName, List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException {
public IQueryParameterOr<?> parse(FhirContext theContext, String theParamName, List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException {
IQueryParameterOr<?> dt;
try {
dt = newInstance();
@ -52,10 +52,10 @@ final class QueryParameterOrBinder extends BaseBinder<IQueryParameterOr<?>> impl
return dt;
}
if (theString.size() > 1) {
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.");
throw new InvalidRequestException("Multiple values detected for non-repeatable parameter '" + theParamName + "'. This server is not configured to allow multiple (AND/OR) values for this param.");
}
dt.setValuesAsQueryTokens(theString.get(0));
dt.setValuesAsQueryTokens(theContext, theParamName, theString.get(0));
} catch (SecurityException e) {
throw new InternalErrorException(e);
}

View File

@ -41,12 +41,12 @@ final class QueryParameterTypeBinder extends BaseBinder<IQueryParameterType> imp
@Override
public List<IQueryParameterOr<?>> encode(FhirContext theContext, IQueryParameterType theValue) throws InternalErrorException {
IQueryParameterType param = theValue;
List<?> retVal = Collections.singletonList(MethodUtil.singleton(param));
List<?> retVal = Collections.singletonList(MethodUtil.singleton(param, null));
return (List<IQueryParameterOr<?>>) retVal;
}
@Override
public IQueryParameterType parse(String theName, List<QualifiedParamList> theParams) throws InternalErrorException, InvalidRequestException {
public IQueryParameterType parse(FhirContext theContext, String theParamName, List<QualifiedParamList> theParams) throws InternalErrorException, InvalidRequestException {
String value = theParams.get(0).get(0);
if (StringUtils.isBlank(value)) {
return null;
@ -58,10 +58,10 @@ final class QueryParameterTypeBinder extends BaseBinder<IQueryParameterType> imp
return dt;
}
if (theParams.size() > 1 || theParams.get(0).size() > 1) {
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.");
throw new InvalidRequestException("Multiple values detected for non-repeatable parameter '" + theParamName + "'. This server is not configured to allow multiple (AND/OR) values for this param.");
}
dt.setValueAsQueryToken(theParams.get(0).getQualifier(), value);
dt.setValueAsQueryToken(theContext, theParamName, theParams.get(0).getQualifier(), value);
return dt;
}

View File

@ -234,7 +234,7 @@ public class SearchParameter extends BaseQueryParameter {
*/
@Override
public Object parse(FhirContext theContext, List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException {
return myParamBinder.parse(getName(), theString);
return myParamBinder.parse(theContext, getName(), theString);
}
public void setChainlists(String[] theChainWhitelist, String[] theChainBlacklist) {

View File

@ -23,6 +23,7 @@ package ca.uhn.fhir.rest.param;
import java.util.ArrayList;
import java.util.List;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IQueryParameterAnd;
import ca.uhn.fhir.model.api.IQueryParameterOr;
import ca.uhn.fhir.rest.method.QualifiedParamList;
@ -40,11 +41,11 @@ public abstract class BaseAndListParam<T extends IQueryParameterOr<?>> implement
public abstract BaseAndListParam<T> addAnd(T theValue);
@Override
public void setValuesAsQueryTokens(List<QualifiedParamList> theParameters) throws InvalidRequestException {
public void setValuesAsQueryTokens(FhirContext theContext, String theParamName, List<QualifiedParamList> theParameters) throws InvalidRequestException {
myValues.clear();
for (QualifiedParamList nextParam : theParameters) {
T nextList = newInstance();
nextList.setValuesAsQueryTokens(nextParam);
nextList.setValuesAsQueryTokens(theContext, theParamName, nextParam);
myValues.add(nextList);
}
}

View File

@ -23,6 +23,7 @@ package ca.uhn.fhir.rest.param;
import java.util.ArrayList;
import java.util.List;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IQueryParameterOr;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.method.QualifiedParamList;
@ -37,11 +38,11 @@ abstract class BaseOrListParam<MT extends BaseOrListParam<?, ?>, PT extends IQue
// }
@Override
public void setValuesAsQueryTokens(QualifiedParamList theParameters) {
public void setValuesAsQueryTokens(FhirContext theContext, String theParamName, QualifiedParamList theParameters) {
myList.clear();
for (String next : theParameters) {
PT nextParam = newInstance();
nextParam.setValueAsQueryToken(theParameters.getQualifier(), next);
nextParam.setValueAsQueryToken(theContext, theParamName, theParameters.getQualifier(), next);
myList.add(nextParam);
}
}

View File

@ -1,5 +1,7 @@
package ca.uhn.fhir.rest.param;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import ca.uhn.fhir.context.FhirContext;
/*
@ -24,6 +26,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
/**
* Base class for RESTful operation parameter types
@ -32,6 +35,12 @@ abstract class BaseParam implements IQueryParameterType {
private Boolean myMissing;
abstract String doGetQueryParameterQualifier();
abstract String doGetValueAsQueryToken(FhirContext theContext);
abstract void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue);
/**
* If set to non-null value, indicates that this parameter has been populated with a "[name]:missing=true" or "[name]:missing=false" vale instead of a normal value
*/
@ -48,10 +57,6 @@ abstract class BaseParam implements IQueryParameterType {
return doGetQueryParameterQualifier();
}
abstract String doGetQueryParameterQualifier();
abstract String doGetValueAsQueryToken(FhirContext theContext);
@Override
public final String getValueAsQueryToken(FhirContext theContext) {
if (myMissing != null) {
@ -60,6 +65,13 @@ abstract class BaseParam implements IQueryParameterType {
return doGetValueAsQueryToken(theContext);
}
/**
* Does this parameter type support chained parameters (only reference should return <code>true</code> for this)
*/
protected boolean isSupportsChain() {
return false;
}
/**
* If set to non-null value, indicates that this parameter has been populated
* with a "[name]:missing=true" or "[name]:missing=false" vale instead of a
@ -74,17 +86,21 @@ abstract class BaseParam implements IQueryParameterType {
}
@Override
public final void setValueAsQueryToken(String theQualifier, String theValue) {
public final void setValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) {
if (Constants.PARAMQUALIFIER_MISSING.equals(theQualifier)) {
myMissing = "true".equals(theValue);
doSetValueAsQueryToken(null, null);
doSetValueAsQueryToken(theContext, theParamName, null, null);
} else {
if (isNotBlank(theQualifier) && theQualifier.charAt(0) == '.') {
if (!isSupportsChain()) {
String msg = theContext.getLocalizer().getMessage(BaseParam.class, "chainNotSupported", theParamName + theQualifier, theQualifier);
throw new InvalidRequestException(msg);
}
}
myMissing = null;
doSetValueAsQueryToken(theQualifier, theValue);
doSetValueAsQueryToken(theContext, theParamName, theQualifier, theValue);
}
}
abstract void doSetValueAsQueryToken(String theQualifier, String theValue);
}

View File

@ -78,18 +78,18 @@ public class CompositeParam<A extends IQueryParameterType, B extends IQueryParam
}
@Override
void doSetValueAsQueryToken(String theQualifier, String theValue) {
void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) {
if (isBlank(theValue)) {
myLeftType.setValueAsQueryToken(theQualifier, "");
myRightType.setValueAsQueryToken(theQualifier, "");
myLeftType.setValueAsQueryToken(theContext, theParamName, theQualifier, "");
myRightType.setValueAsQueryToken(theContext, theParamName, theQualifier, "");
} else {
List<String> parts = ParameterUtil.splitParameterString(theValue, '$', false);
if (parts.size() > 2) {
throw new InvalidRequestException("Invalid value for composite parameter (only one '$' is valid for this parameter, others must be escaped). Value was: " + theValue);
}
myLeftType.setValueAsQueryToken(theQualifier, parts.get(0));
myLeftType.setValueAsQueryToken(theContext, theParamName, theQualifier, parts.get(0));
if (parts.size() > 1) {
myRightType.setValueAsQueryToken(theQualifier, parts.get(1));
myRightType.setValueAsQueryToken(theContext, theParamName, theQualifier, parts.get(1));
}
}
}

View File

@ -162,7 +162,7 @@ public class DateParam extends BaseParamWithPrefix<DateParam> implements IQueryP
* The string
*/
public DateParam(String theString) {
setValueAsQueryToken(null, theString);
setValueAsQueryToken(null, null, null, theString);
}
@Override
@ -185,7 +185,7 @@ public class DateParam extends BaseParamWithPrefix<DateParam> implements IQueryP
}
@Override
void doSetValueAsQueryToken(String theQualifier, String theValue) {
void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) {
setValueAsString(theValue);
}
@ -285,7 +285,7 @@ public class DateParam extends BaseParamWithPrefix<DateParam> implements IQueryP
}
@Override
public void setValuesAsQueryTokens(QualifiedParamList theParameters) {
public void setValuesAsQueryTokens(FhirContext theContext, String theParamName, QualifiedParamList theParameters) {
setMissing(null);
setPrefix(null);
setValueAsString(null);

View File

@ -28,6 +28,7 @@ import java.util.List;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IQueryParameterAnd;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.method.QualifiedParamList;
@ -357,7 +358,7 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
}
@Override
public void setValuesAsQueryTokens(List<QualifiedParamList> theParameters) throws InvalidRequestException {
public void setValuesAsQueryTokens(FhirContext theContext, String theParamName, List<QualifiedParamList> theParameters) throws InvalidRequestException {
boolean haveHadUnqualifiedParameter = false;
for (QualifiedParamList paramList : theParameters) {
@ -376,7 +377,7 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
param = param.replace(' ', '+');
DateParam parsed = new DateParam();
parsed.setValueAsQueryToken(paramList.getQualifier(), param);
parsed.setValueAsQueryToken(theContext, theParamName, paramList.getQualifier(), param);
addParam(parsed);
if (parsed.getPrefix() == null) {

View File

@ -62,7 +62,7 @@ public class HasParam extends BaseParam implements IQueryParameterType {
}
@Override
void doSetValueAsQueryToken(String theQualifier, String theValue) {
void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) {
String qualifier = defaultString(theQualifier);
if (!qualifier.startsWith(":")) {
throwInvalidSyntaxException(Constants.PARAM_HAS + qualifier);

View File

@ -28,7 +28,6 @@ import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.model.api.IQueryParameterType;
public class NumberParam extends BaseParamWithPrefix<NumberParam> implements IQueryParameterType {
@ -49,7 +48,7 @@ public class NumberParam extends BaseParamWithPrefix<NumberParam> implements IQu
* A string value, e.g. "&gt;5.0"
*/
public NumberParam(String theValue) {
setValueAsQueryToken(null, theValue);
setValueAsQueryToken(null, null, null, theValue);
}
@Override
@ -68,7 +67,7 @@ public class NumberParam extends BaseParamWithPrefix<NumberParam> implements IQu
}
@Override
void doSetValueAsQueryToken(String theQualifier, String theValue) {
void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) {
if (getMissing() != null && isBlank(theValue)) {
return;
}

View File

@ -183,7 +183,7 @@ public class QuantityParam extends BaseParamWithPrefix<QuantityParam> implements
* A quantity value (with no system or units), such as "100.0" or "gt4"
*/
public QuantityParam(String theQuantity) {
setValueAsQueryToken(null, theQuantity);
setValueAsQueryToken(null, null, null, theQuantity);
}
/**
@ -193,7 +193,7 @@ public class QuantityParam extends BaseParamWithPrefix<QuantityParam> implements
* A quantity value (with no system or units), such as <code>100</code>
*/
public QuantityParam(long theQuantity) {
setValueAsQueryToken(null, Long.toString(theQuantity));
setValueAsQueryToken(null, null, null, Long.toString(theQuantity));
}
/**
@ -207,7 +207,7 @@ public class QuantityParam extends BaseParamWithPrefix<QuantityParam> implements
* The unit code
*/
public QuantityParam(String theQuantity, String theSystem, String theUnits) {
setValueAsQueryToken(null, theQuantity);
setValueAsQueryToken(null, null, null, theQuantity);
setSystem(theSystem);
setUnits(theUnits);
}
@ -248,7 +248,7 @@ public class QuantityParam extends BaseParamWithPrefix<QuantityParam> implements
}
@Override
void doSetValueAsQueryToken(String theQualifier, String theValue) {
void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) {
clear();
if (theValue == null) {

View File

@ -35,9 +35,9 @@ import ca.uhn.fhir.util.CoverageIgnore;
public class ReferenceParam extends BaseParam implements IQueryParameterType {
private final IdDt myId = new IdDt();
private String myChain;
private final IdDt myId = new IdDt();
/**
* Constructor
*/
@ -49,14 +49,14 @@ public class ReferenceParam extends BaseParam implements IQueryParameterType {
* Constructor
*/
public ReferenceParam(String theValue) {
setValueAsQueryToken(null, theValue);
setValueAsQueryToken(null, null, null, theValue);
}
/**
* Constructor
*/
public ReferenceParam(String theChain, String theValue) {
setValueAsQueryToken(null, theValue);
setValueAsQueryToken(null, null, null, theValue);
setChain(theChain);
}
@ -72,118 +72,6 @@ public class ReferenceParam extends BaseParam implements IQueryParameterType {
setChain(theChain);
}
public void setValue(String theValue) {
myId.setValue(theValue);
}
public String getChain() {
return myChain;
}
public Class<? extends IBaseResource> getResourceType(FhirContext theCtx) {
if (isBlank(getResourceType())) {
return null;
}
return theCtx.getResourceDefinition(getResourceType()).getImplementingClass();
}
public void setChain(String theChain) {
myChain = theChain;
}
/**
* Returns a new param containing the same value as this param, but with the type copnverted
* to {@link DateParam}. This is useful if you are using reference parameters and want to handle
* chained parameters of different types in a single method.
* <p>
* See <a href="http://jamesagnew.github.io/hapi-fhir/doc_rest_operations.html#dynamic_chains">Dynamic Chains</a>
* in the HAPI FHIR documentation for an example of how to use this method.
* </p>
*/
public DateParam toDateParam(FhirContext theContext) {
DateParam retVal = new DateParam();
retVal.setValueAsQueryToken(null, getValueAsQueryToken(theContext));
return retVal;
}
/**
* Returns a new param containing the same value as this param, but with the type copnverted
* to {@link NumberParam}. This is useful if you are using reference parameters and want to handle
* chained parameters of different types in a single method.
* <p>
* See <a href="http://jamesagnew.github.io/hapi-fhir/doc_rest_operations.html#dynamic_chains">Dynamic Chains</a>
* in the HAPI FHIR documentation for an example of how to use this method.
* </p>
*/
public NumberParam toNumberParam(FhirContext theContext) {
NumberParam retVal = new NumberParam();
retVal.setValueAsQueryToken(null, getValueAsQueryToken(theContext));
return retVal;
}
/**
* Returns a new param containing the same value as this param, but with the type copnverted
* to {@link QuantityParam}. This is useful if you are using reference parameters and want to handle
* chained parameters of different types in a single method.
* <p>
* See <a href="http://jamesagnew.github.io/hapi-fhir/doc_rest_operations.html#dynamic_chains">Dynamic Chains</a>
* in the HAPI FHIR documentation for an example of how to use this method.
* </p>
*/
public QuantityParam toQuantityParam(FhirContext theContext) {
QuantityParam retVal = new QuantityParam();
retVal.setValueAsQueryToken(null, getValueAsQueryToken(theContext));
return retVal;
}
@Override
public String toString() {
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
if (isNotBlank(myChain)) {
b.append("chain", myChain);
}
b.append("value", getValue());
return b.build();
}
public String getValue() {
return myId.getValue();
}
/**
* Returns a new param containing the same value as this param, but with the type copnverted
* to {@link StringParam}. This is useful if you are using reference parameters and want to handle
* chained parameters of different types in a single method.
* <p>
* See <a href="http://jamesagnew.github.io/hapi-fhir/doc_rest_operations.html#dynamic_chains">Dynamic Chains</a>
* in the HAPI FHIR documentation for an example of how to use this method.
* </p>
*/
public StringParam toStringParam(FhirContext theContext) {
StringParam retVal = new StringParam();
retVal.setValueAsQueryToken(null, getValueAsQueryToken(theContext));
return retVal;
}
/**
* Returns a new param containing the same value as this param, but with the type copnverted
* to {@link TokenParam}. This is useful if you are using reference parameters and want to handle
* chained parameters of different types in a single method.
* <p>
* See <a href="http://jamesagnew.github.io/hapi-fhir/doc_rest_operations.html#dynamic_chains">Dynamic Chains</a>
* in the HAPI FHIR documentation for an example of how to use this method.
* </p>
*/
public TokenParam toTokenParam(FhirContext theContext) {
TokenParam retVal = new TokenParam();
retVal.setValueAsQueryToken(null, getValueAsQueryToken(theContext));
return retVal;
}
@Override
String doGetQueryParameterQualifier() {
StringBuilder b = new StringBuilder();
@ -201,10 +89,6 @@ public class ReferenceParam extends BaseParam implements IQueryParameterType {
return null;
}
public String getResourceType() {
return myId.getResourceType();
}
@Override
String doGetValueAsQueryToken(FhirContext theContext) {
if (isBlank(myId.getResourceType())) {
@ -215,7 +99,7 @@ public class ReferenceParam extends BaseParam implements IQueryParameterType {
}
@Override
void doSetValueAsQueryToken(String theQualifier, String theValue) {
void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) {
String q = theQualifier;
String resourceType = null;
if (isNotBlank(q)) {
@ -239,27 +123,148 @@ public class ReferenceParam extends BaseParam implements IQueryParameterType {
}
}
@CoverageIgnore
public String getBaseUrl() {
return myId.getBaseUrl();
}
public String getChain() {
return myChain;
}
@CoverageIgnore
public String getIdPart() {
return myId.getIdPart();
}
@CoverageIgnore
public Long getIdPartAsLong() {
return myId.getIdPartAsLong();
}
@CoverageIgnore
public BigDecimal getIdPartAsBigDecimal() {
return myId.getIdPartAsBigDecimal();
}
@CoverageIgnore
public String getBaseUrl() {
return myId.getBaseUrl();
public Long getIdPartAsLong() {
return myId.getIdPartAsLong();
}
public String getResourceType() {
return myId.getResourceType();
}
public Class<? extends IBaseResource> getResourceType(FhirContext theCtx) {
if (isBlank(getResourceType())) {
return null;
}
return theCtx.getResourceDefinition(getResourceType()).getImplementingClass();
}
public String getValue() {
return myId.getValue();
}
public boolean hasResourceType() {
return myId.hasResourceType();
}
@Override
protected boolean isSupportsChain() {
return true;
}
public void setChain(String theChain) {
myChain = theChain;
}
public void setValue(String theValue) {
myId.setValue(theValue);
}
/**
* Returns a new param containing the same value as this param, but with the type copnverted
* to {@link DateParam}. This is useful if you are using reference parameters and want to handle
* chained parameters of different types in a single method.
* <p>
* See <a href="http://jamesagnew.github.io/hapi-fhir/doc_rest_operations.html#dynamic_chains">Dynamic Chains</a>
* in the HAPI FHIR documentation for an example of how to use this method.
* </p>
*/
public DateParam toDateParam(FhirContext theContext) {
DateParam retVal = new DateParam();
retVal.setValueAsQueryToken(theContext, null, null, getValueAsQueryToken(theContext));
return retVal;
}
/**
* Returns a new param containing the same value as this param, but with the type copnverted
* to {@link NumberParam}. This is useful if you are using reference parameters and want to handle
* chained parameters of different types in a single method.
* <p>
* See <a href="http://jamesagnew.github.io/hapi-fhir/doc_rest_operations.html#dynamic_chains">Dynamic Chains</a>
* in the HAPI FHIR documentation for an example of how to use this method.
* </p>
*/
public NumberParam toNumberParam(FhirContext theContext) {
NumberParam retVal = new NumberParam();
retVal.setValueAsQueryToken(theContext, null, null, getValueAsQueryToken(theContext));
return retVal;
}
/**
* Returns a new param containing the same value as this param, but with the type copnverted
* to {@link QuantityParam}. This is useful if you are using reference parameters and want to handle
* chained parameters of different types in a single method.
* <p>
* See <a href="http://jamesagnew.github.io/hapi-fhir/doc_rest_operations.html#dynamic_chains">Dynamic Chains</a>
* in the HAPI FHIR documentation for an example of how to use this method.
* </p>
*/
public QuantityParam toQuantityParam(FhirContext theContext) {
QuantityParam retVal = new QuantityParam();
retVal.setValueAsQueryToken(theContext, null, null, getValueAsQueryToken(theContext));
return retVal;
}
@Override
public String toString() {
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
if (isNotBlank(myChain)) {
b.append("chain", myChain);
}
b.append("value", getValue());
return b.build();
}
/**
* Returns a new param containing the same value as this param, but with the type copnverted
* to {@link StringParam}. This is useful if you are using reference parameters and want to handle
* chained parameters of different types in a single method.
* <p>
* See <a href="http://jamesagnew.github.io/hapi-fhir/doc_rest_operations.html#dynamic_chains">Dynamic Chains</a>
* in the HAPI FHIR documentation for an example of how to use this method.
* </p>
*/
public StringParam toStringParam(FhirContext theContext) {
StringParam retVal = new StringParam();
retVal.setValueAsQueryToken(theContext, null, null, getValueAsQueryToken(theContext));
return retVal;
}
/**
* Returns a new param containing the same value as this param, but with the type copnverted
* to {@link TokenParam}. This is useful if you are using reference parameters and want to handle
* chained parameters of different types in a single method.
* <p>
* See <a href="http://jamesagnew.github.io/hapi-fhir/doc_rest_operations.html#dynamic_chains">Dynamic Chains</a>
* in the HAPI FHIR documentation for an example of how to use this method.
* </p>
*/
public TokenParam toTokenParam(FhirContext theContext) {
TokenParam retVal = new TokenParam();
retVal.setValueAsQueryToken(theContext, null, null, getValueAsQueryToken(theContext));
return retVal;
}
}

View File

@ -65,7 +65,7 @@ public class StringParam extends BaseParam implements IQueryParameterType {
}
@Override
void doSetValueAsQueryToken(String theQualifier, String theValue) {
void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) {
if (Constants.PARAMQUALIFIER_STRING_EXACT.equals(theQualifier)) {
setExact(true);
} else {

View File

@ -107,7 +107,7 @@ public class TokenParam extends BaseParam implements IQueryParameterType {
* {@inheritDoc}
*/
@Override
void doSetValueAsQueryToken(String theQualifier, String theParameter) {
void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theParameter) {
setModifier(null);
if (theQualifier != null) {
TokenParamModifier modifier = TokenParamModifier.forValue(theQualifier);

View File

@ -57,7 +57,7 @@ public class UriParam extends BaseParam implements IQueryParameterType {
}
@Override
void doSetValueAsQueryToken(String theQualifier, String theValue) {
void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) {
myQualifier = UriParamQualifierEnum.forValue(theQualifier);
myValue = ParameterUtil.unescape(theValue);
}

View File

@ -22,6 +22,7 @@ package ca.uhn.fhir.rest.server;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
@ -651,13 +652,15 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
* This is basically the end of processing for a successful request, since the
* method binding replies to the client and closes the response.
*/
resourceMethod.invokeServer(this, requestDetails);
Closeable outputStreamOrWriter = (Closeable) resourceMethod.invokeServer(this, requestDetails);
for (int i = getInterceptors().size() - 1; i >= 0; i--) {
IServerInterceptor next = getInterceptors().get(i);
next.processingCompletedNormally(requestDetails);
}
outputStreamOrWriter.close();
} catch (NotModifiedException e) {
for (int i = getInterceptors().size() - 1; i >= 0; i--) {
@ -1141,24 +1144,19 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
if (allowPrefer) {
addContentLocationHeaders(theRequest, servletResponse, response, resourceName);
}
Writer writer;
if (outcome != null) {
ResponseEncoding encoding = RestfulServerUtils.determineResponseEncodingWithDefault(theRequest);
servletResponse.setContentType(encoding.getResourceContentType());
Writer writer = servletResponse.getWriter();
writer = servletResponse.getWriter();
IParser parser = encoding.getEncoding().newParser(getFhirContext());
parser.setPrettyPrint(RestfulServerUtils.prettyPrintResponse(this, theRequest));
try {
outcome.execute(parser, writer);
} finally {
writer.close();
}
outcome.execute(parser, writer);
} else {
servletResponse.setContentType(Constants.CT_TEXT_WITH_UTF8);
Writer writer = servletResponse.getWriter();
writer.close();
writer = servletResponse.getWriter();
}
// getMethod().in
return null;
return writer;
}
@Override

View File

@ -21,6 +21,7 @@ package ca.uhn.fhir.rest.server.interceptor;
*/
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.Closeable;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
@ -51,7 +52,8 @@ public class ExceptionHandlingInterceptor extends InterceptorAdapter {
@Override
public boolean handleException(RequestDetails theRequestDetails, BaseServerResponseException theException, HttpServletRequest theRequest, HttpServletResponse theResponse) throws ServletException, IOException {
handleException(theRequestDetails, theException);
Closeable writer = (Closeable) handleException(theRequestDetails, theException);
writer.close();
return false;
}

View File

@ -1,7 +1,5 @@
package ca.uhn.fhir.rest.server.servlet;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
/*
* #%L
* HAPI FHIR - Core Library
@ -52,13 +50,12 @@ public class ServletRestfulResponse extends RestfulResponse<ServletRequestDetail
theHttpResponse.setStatus(stausCode);
theHttpResponse.setContentType(contentType);
if (bin.getContent() == null || bin.getContent().length == 0) {
return null;
return theHttpResponse.getOutputStream();
} else {
theHttpResponse.setContentLength(bin.getContent().length);
ServletOutputStream oos = theHttpResponse.getOutputStream();
oos.write(bin.getContent());
oos.close();
return null;
return oos;
}
}
@ -86,9 +83,8 @@ public class ServletRestfulResponse extends RestfulResponse<ServletRequestDetail
}
@Override
public final Object sendWriterResponse(int status, String contentType, String charset, Writer writer) throws IOException {
writer.close();
return null;
public final Object sendWriterResponse(int theStatus, String theContentType, String theCharset, Writer theWriter) throws IOException {
return theWriter;
}
@Override

View File

@ -36,6 +36,8 @@ ca.uhn.fhir.rest.method.SearchMethodBinding.idNullForCompartmentSearch=ID parame
ca.uhn.fhir.rest.method.SummaryEnumParameter.cantCombineText=Can not combine _summary=text with other values for _summary
ca.uhn.fhir.rest.param.BaseParam.chainNotSupported=Invalid search parameter "{0}". Parameter contains a chain ({1}) and chains are not supported for this parameter (chaining is only allowed on reference parameters)
ca.uhn.fhir.rest.param.ResourceParameter.invalidContentTypeInRequest=Incorrect Content-Type header value of "{0}" was provided in the request. A FHIR Content-Type is required for "{1}" operation
ca.uhn.fhir.rest.param.ResourceParameter.noContentTypeInRequest=No Content-Type header was provided in the request. This is required for "{0}" operation
ca.uhn.fhir.rest.param.ResourceParameter.failedToParseRequest=Failed to parse request body as {0} resource. Error was: {1}

View File

@ -927,7 +927,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
public <R extends IBaseResource> Set<Long> processMatchUrl(String theMatchUrl, Class<R> theResourceType) {
RuntimeResourceDefinition resourceDef = getContext().getResourceDefinition(theResourceType);
SearchParameterMap paramMap = translateMatchUrl(theMatchUrl, resourceDef);
SearchParameterMap paramMap = translateMatchUrl(myContext, theMatchUrl, resourceDef);
paramMap.setPersistResults(false);
if (paramMap.isEmpty() && paramMap.getLastUpdated() == null) {
@ -1688,7 +1688,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
return parameters;
}
public static SearchParameterMap translateMatchUrl(String theMatchUrl, RuntimeResourceDefinition resourceDef) {
public static SearchParameterMap translateMatchUrl(FhirContext theContext, String theMatchUrl, RuntimeResourceDefinition resourceDef) {
SearchParameterMap paramMap = new SearchParameterMap();
List<NameValuePair> parameters = translateMatchUrl(theMatchUrl);
@ -1723,7 +1723,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - Can not have more than 2 " + Constants.PARAM_LASTUPDATED + " parameter repetitions");
} else {
DateRangeParam p1 = new DateRangeParam();
p1.setValuesAsQueryTokens(paramList);
p1.setValuesAsQueryTokens(theContext, nextParamName, paramList);
paramMap.setLastUpdated(p1);
}
}
@ -1731,7 +1731,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
}
if (Constants.PARAM_HAS.equals(nextParamName)) {
IQueryParameterAnd<?> param = MethodUtil.parseQueryParams(RestSearchParameterTypeEnum.HAS, nextParamName, paramList);
IQueryParameterAnd<?> param = MethodUtil.parseQueryParams(theContext, RestSearchParameterTypeEnum.HAS, nextParamName, paramList);
paramMap.add(nextParamName, param);
continue;
}
@ -1753,7 +1753,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
throw new InvalidRequestException("Invalid parameter chain: " + nextParamName + paramList.get(0).getQualifier());
}
IQueryParameterAnd<?> type = newInstanceAnd(nextParamName);
type.setValuesAsQueryTokens((paramList));
type.setValuesAsQueryTokens(theContext, nextParamName, (paramList));
paramMap.add(nextParamName, type);
} else if (nextParamName.startsWith("_")) {
// ignore these since they aren't search params (e.g. _sort)
@ -1763,7 +1763,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - Resource type " + resourceDef.getName() + " does not have a parameter with name: " + nextParamName);
}
IQueryParameterAnd<?> param = MethodUtil.parseQueryParams(paramDef, nextParamName, paramList);
IQueryParameterAnd<?> param = MethodUtil.parseQueryParams(theContext, paramDef, nextParamName, paramList);
paramMap.add(nextParamName, param);
}
}

View File

@ -65,7 +65,6 @@ import ca.uhn.fhir.rest.param.ParamPrefixEnum;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2<Subscription>implements IFhirResourceDaoSubscription<Subscription> {
@ -148,7 +147,7 @@ public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2<Subsc
private int pollForNewUndeliveredResources(SubscriptionTable theSubscriptionTable) {
Subscription subscription = toResource(Subscription.class, theSubscriptionTable.getSubscriptionResource(), false);
RuntimeResourceDefinition resourceDef = validateCriteriaAndReturnResourceDefinition(subscription);
SearchParameterMap criteriaUrl = translateMatchUrl(subscription.getCriteria(), resourceDef);
SearchParameterMap criteriaUrl = translateMatchUrl(getContext(), subscription.getCriteria(), resourceDef);
criteriaUrl = new SearchParameterMap();
long start = theSubscriptionTable.getMostRecentMatch().getTime();

View File

@ -617,11 +617,11 @@ public class SearchBuilder {
}
chainValue = new ReferenceParam();
chainValue.setValueAsQueryToken(qualifier, resourceId);
chainValue.setValueAsQueryToken(myContext, theParamName, qualifier, resourceId);
((ReferenceParam) chainValue).setChain(remainingChain);
} else if (isMeta) {
IQueryParameterType type = BaseHapiFhirDao.newInstanceType(chain);
type.setValueAsQueryToken(qualifier, resourceId);
type.setValueAsQueryToken(myContext, theParamName, qualifier, resourceId);
chainValue = type;
} else {
chainValue = toParameterType(param, qualifier, resourceId);
@ -1998,7 +1998,7 @@ public class SearchBuilder {
private IQueryParameterType toParameterType(RuntimeSearchParam theParam, String theQualifier, String theValueAsQueryToken) {
IQueryParameterType qp = toParameterType(theParam);
qp.setValueAsQueryToken(theQualifier, theValueAsQueryToken); // aaaa
qp.setValueAsQueryToken(myContext, theParam.getName(), theQualifier, theValueAsQueryToken);
return qp;
}

View File

@ -152,7 +152,7 @@ public class FhirResourceDaoSubscriptionDstu3 extends FhirResourceDaoDstu3<Subsc
private int pollForNewUndeliveredResources(SubscriptionTable theSubscriptionTable) {
Subscription subscription = toResource(Subscription.class, theSubscriptionTable.getSubscriptionResource(), false);
RuntimeResourceDefinition resourceDef = validateCriteriaAndReturnResourceDefinition(subscription);
SearchParameterMap criteriaUrl = translateMatchUrl(subscription.getCriteria(), resourceDef);
SearchParameterMap criteriaUrl = translateMatchUrl(getContext(), subscription.getCriteria(), resourceDef);
criteriaUrl = new SearchParameterMap();
long start = theSubscriptionTable.getMostRecentMatch().getTime();

View File

@ -27,7 +27,7 @@ public class BaseFhirDaoTest extends BaseJpaTest {
@Test
public void testTranslateMatchUrl() {
SearchParameterMap match = BaseHapiFhirDao.translateMatchUrl("Condition?patient=304&_lastUpdated=>2011-01-01T11:12:21.0000Z", ourCtx.getResourceDefinition(Condition.class));
SearchParameterMap match = BaseHapiFhirDao.translateMatchUrl(ourCtx, "Condition?patient=304&_lastUpdated=>2011-01-01T11:12:21.0000Z", ourCtx.getResourceDefinition(Condition.class));
assertEquals("2011-01-01T11:12:21.0000Z", match.getLastUpdated().getLowerBound().getValueAsString());
assertEquals(ReferenceParam.class, match.get("patient").get(0).get(0).getClass());
assertEquals("304", ((ReferenceParam)match.get("patient").get(0).get(0)).getIdPart());

View File

@ -16,7 +16,7 @@ public class CodingDtTest {
@Test
public void testTokenNoSystem() {
CodingDt dt = new CodingDt();
dt.setValueAsQueryToken(null, "c");
dt.setValueAsQueryToken(ourCtx, null, null, "c");
assertEquals(null, dt.getSystem().getValueAsString());
assertEquals("c", dt.getCode().getValue());
@ -26,7 +26,7 @@ public class CodingDtTest {
@Test
public void testTokenWithPipeInValue() {
CodingDt dt = new CodingDt();
dt.setValueAsQueryToken(null, "a|b|c");
dt.setValueAsQueryToken(ourCtx, null, null, "a|b|c");
assertEquals("a", dt.getSystem().getValueAsString());
assertEquals("b|c", dt.getCode().getValue());
@ -36,7 +36,7 @@ public class CodingDtTest {
@Test
public void testTokenWithPipeInValueAndNoSystem() {
CodingDt dt = new CodingDt();
dt.setValueAsQueryToken(null, "|b\\|c");
dt.setValueAsQueryToken(ourCtx, null, null, "|b\\|c");
assertEquals("", dt.getSystem().getValueAsString());
assertEquals("b|c", dt.getCode().getValue());
@ -50,7 +50,7 @@ public class CodingDtTest {
@Test
public void testTokenWithPipeInValueAndNoSystemAndBeLenient() {
CodingDt dt = new CodingDt();
dt.setValueAsQueryToken(null, "|b|c");
dt.setValueAsQueryToken(ourCtx, null, null, "|b|c");
assertEquals("", dt.getSystem().getValueAsString());
assertEquals("b|c", dt.getCode().getValue());

View File

@ -15,7 +15,7 @@ public class IdentifierDtTest {
@Test
public void testTokenNoSystem() {
IdentifierDt dt = new IdentifierDt();
dt.setValueAsQueryToken(null, "c");
dt.setValueAsQueryToken(ourCtx, null, null, "c");
assertEquals(null, dt.getSystem().getValueAsString());
assertEquals("c", dt.getValue().getValue());
@ -25,7 +25,7 @@ public class IdentifierDtTest {
@Test
public void testTokenWithPipeInValue() {
IdentifierDt dt = new IdentifierDt();
dt.setValueAsQueryToken(null, "a|b|c");
dt.setValueAsQueryToken(ourCtx, null, null, "a|b|c");
assertEquals("a", dt.getSystem().getValueAsString());
assertEquals("b|c", dt.getValue().getValue());
@ -35,7 +35,7 @@ public class IdentifierDtTest {
@Test
public void testTokenWithPipeInValueAndNoSystem() {
IdentifierDt dt = new IdentifierDt();
dt.setValueAsQueryToken(null, "|b\\|c");
dt.setValueAsQueryToken(ourCtx, null, null, "|b\\|c");
assertEquals("", dt.getSystem().getValueAsString());
assertEquals("b|c", dt.getValue().getValue());
@ -49,7 +49,7 @@ public class IdentifierDtTest {
@Test
public void testTokenWithPipeInValueAndNoSystemAndBeLenient() {
IdentifierDt dt = new IdentifierDt();
dt.setValueAsQueryToken(null, "|b|c");
dt.setValueAsQueryToken(ourCtx, null, null, "|b|c");
assertEquals("", dt.getSystem().getValueAsString());
assertEquals("b|c", dt.getValue().getValue());

View File

@ -13,6 +13,7 @@ import java.util.TimeZone;
import org.junit.AfterClass;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.model.primitive.DateTimeDt;
@ -183,10 +184,12 @@ public class DateRangeParamTest {
if (theUpper != null) {
tokens.add(QualifiedParamList.singleton(null, theUpper));
}
p.setValuesAsQueryTokens(tokens);
p.setValuesAsQueryTokens(ourCtx, null, tokens);
return p;
}
private static FhirContext ourCtx = FhirContext.forDstu1();
public static Date parse(String theString) throws ParseException {
return ourFmt.parse(theString);
}

View File

@ -15,7 +15,7 @@ public class QuantityParamTest {
@Test
public void testFull() {
QuantityParam p = new QuantityParam();
p.setValueAsQueryToken(null, "<5.4|http://unitsofmeasure.org|mg");
p.setValueAsQueryToken(ourCtx, null, null, "<5.4|http://unitsofmeasure.org|mg");
assertEquals(QuantityCompararatorEnum.LESSTHAN,p.getComparator());
assertEquals("5.4", p.getValue().toPlainString());
assertEquals("http://unitsofmeasure.org", p.getSystem());
@ -26,7 +26,7 @@ public class QuantityParamTest {
@Test
public void testApproximate() {
QuantityParam p = new QuantityParam();
p.setValueAsQueryToken(null, "~5.4|http://unitsofmeasure.org|mg");
p.setValueAsQueryToken(ourCtx, null, null, "~5.4|http://unitsofmeasure.org|mg");
assertEquals(null,p.getComparator());
assertEquals(true, p.isApproximate());
assertEquals("5.4", p.getValue().toPlainString());
@ -39,7 +39,7 @@ public class QuantityParamTest {
@Test
public void testNoQualifier() {
QuantityParam p = new QuantityParam();
p.setValueAsQueryToken(null, "5.4|http://unitsofmeasure.org|mg");
p.setValueAsQueryToken(ourCtx, null, null, "5.4|http://unitsofmeasure.org|mg");
assertEquals(null, p.getComparator());
assertEquals("5.4", p.getValue().toPlainString());
assertEquals("http://unitsofmeasure.org", p.getSystem());
@ -51,7 +51,7 @@ public class QuantityParamTest {
@Test
public void testNoUnits() {
QuantityParam p = new QuantityParam();
p.setValueAsQueryToken(null, "5.4");
p.setValueAsQueryToken(ourCtx, null, null, "5.4");
assertEquals(null, p.getComparator());
assertEquals("5.4", p.getValue().toPlainString());
assertEquals(null, p.getSystem());

View File

@ -5,6 +5,7 @@ import static org.junit.Assert.*;
import org.junit.AfterClass;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.util.TestUtil;
public class ReferenceParamTest {
@ -13,7 +14,7 @@ public class ReferenceParamTest {
public void testWithResourceTypeAsQualifier() {
ReferenceParam rp = new ReferenceParam();
rp.setValueAsQueryToken(":Location", "123");
rp.setValueAsQueryToken(ourCtx, null, ":Location", "123");
assertEquals("Location", rp.getResourceType());
assertEquals("123", rp.getIdPart());
@ -23,12 +24,13 @@ public class ReferenceParamTest {
public void testWithResourceType() {
ReferenceParam rp = new ReferenceParam();
rp.setValueAsQueryToken(null, "Location/123");
rp.setValueAsQueryToken(ourCtx, null, null, "Location/123");
assertEquals("Location", rp.getResourceType());
assertEquals("123", rp.getIdPart());
}
private FhirContext ourCtx = FhirContext.forDstu1();
@AfterClass
public static void afterClassClearContext() {

View File

@ -1,6 +1,8 @@
package ca.uhn.fhir.rest.param;
import static org.junit.Assert.*;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dstu.composite.CodingDt;
import ca.uhn.fhir.rest.method.QualifiedParamList;
import ca.uhn.fhir.util.TestUtil;
@ -57,7 +59,7 @@ public class TokenOrListParamTest {
@Test
public void testParseExcaped() {
TokenOrListParam params = new TokenOrListParam();
params.setValuesAsQueryTokens(QualifiedParamList.singleton("system|code-include-but-not-end-with-comma\\,suffix"));
params.setValuesAsQueryTokens(ourCtx, null, QualifiedParamList.singleton("system|code-include-but-not-end-with-comma\\,suffix"));
assertEquals(1, params.getListAsCodings().size());
assertEquals("system", params.getListAsCodings().get(0).getSystemElement().getValue());
@ -65,6 +67,8 @@ public class TokenOrListParamTest {
}
private static FhirContext ourCtx = FhirContext.forDstu1();
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();

View File

@ -2,6 +2,7 @@ package ca.uhn.fhir.rest.server;
import static org.junit.Assert.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@ -44,7 +45,7 @@ public class StringParameterTest {
assertEquals(":contains", sp.getQueryParameterQualifier());
sp = new StringParam("VAL");
sp.setValueAsQueryToken(":contains", "VAL");
sp.setValueAsQueryToken(ourCtx, null, ":contains", "VAL");
assertEquals(true, sp.isContains());
assertEquals("VAL", sp.getValue());
}
@ -54,7 +55,7 @@ public class StringParameterTest {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?plain=aaa");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
@ -63,7 +64,7 @@ public class StringParameterTest {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?plain=BBB");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
@ -76,7 +77,7 @@ public class StringParameterTest {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?str:exact=aaa");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
@ -85,7 +86,7 @@ public class StringParameterTest {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?str:exact=AAA");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
@ -94,7 +95,7 @@ public class StringParameterTest {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?str:exact=BBB");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
@ -107,7 +108,7 @@ public class StringParameterTest {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?ccc:exact=aaa");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
@ -120,7 +121,7 @@ public class StringParameterTest {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?str=aaa");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
@ -130,7 +131,7 @@ public class StringParameterTest {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?str=AAA");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
@ -140,7 +141,7 @@ public class StringParameterTest {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?str=BBB");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
@ -153,7 +154,7 @@ public class StringParameterTest {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?str=aaa&_format=xml&_pretty=true");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());

View File

@ -389,7 +389,7 @@ public class IdentifierDt
* {@inheritDoc}
*/
@Override
public void setValueAsQueryToken(String theQualifier, String theValue) {
public void setValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) {
int barIndex = theValue.indexOf('|');
if (barIndex != -1) {
setSystem(new UriDt(theValue.substring(0, barIndex)));

View File

@ -0,0 +1,142 @@
package ca.uhn.fhir.rest.server;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.hl7.fhir.dstu3.model.HumanName;
import org.hl7.fhir.dstu3.model.OperationOutcome;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.annotation.OptionalParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.param.TokenAndListParam;
import ca.uhn.fhir.util.PortUtil;
import ca.uhn.fhir.util.TestUtil;
public class SearchDstu3Test {
private static CloseableHttpClient ourClient;
private static FhirContext ourCtx = FhirContext.forDstu3();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchDstu3Test.class);
private static int ourPort;
private static Server ourServer;
private static String ourLastMethod;
private static TokenAndListParam ourIdentifiers;
@Before
public void before() {
ourLastMethod = null;
ourIdentifiers = null;
}
@Test
public void testSearchNormal() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar");
CloseableHttpResponse status = ourClient.execute(httpGet);
try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
ourLog.info(responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals("search", ourLastMethod);
assertEquals("foo", ourIdentifiers.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getSystem());
assertEquals("bar", ourIdentifiers.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValue());
} finally {
IOUtils.closeQuietly(status.getEntity().getContent());
}
}
@Test
public void testSearchWithInvalidChain() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier.chain=foo%7Cbar");
CloseableHttpResponse status = ourClient.execute(httpGet);
try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
ourLog.info(responseContent);
assertEquals(400, status.getStatusLine().getStatusCode());
OperationOutcome oo = (OperationOutcome) ourCtx.newXmlParser().parseResource(responseContent);
assertEquals("Invalid search parameter \"identifier.chain\". Parameter contains a chain (.chain) and chains are not supported for this parameter (chaining is only allowed on reference parameters)", oo.getIssueFirstRep().getDiagnostics());
} finally {
IOUtils.closeQuietly(status.getEntity().getContent());
}
}
@AfterClass
public static void afterClassClearContext() throws Exception {
ourServer.stop();
TestUtil.clearAllStaticFieldsForUnitTest();
}
@BeforeClass
public static void beforeClass() throws Exception {
ourPort = PortUtil.findFreePort();
ourServer = new Server(ourPort);
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
ServletHandler proxyHandler = new ServletHandler();
RestfulServer servlet = new RestfulServer(ourCtx);
servlet.setPagingProvider(new FifoMemoryPagingProvider(10));
servlet.setResourceProviders(patientProvider);
ServletHolder servletHolder = new ServletHolder(servlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler);
ourServer.start();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setConnectionManager(connectionManager);
ourClient = builder.build();
}
public static class DummyPatientResourceProvider implements IResourceProvider {
@Override
public Class<? extends IBaseResource> getResourceType() {
return Patient.class;
}
//@formatter:off
@SuppressWarnings("rawtypes")
@Search()
public List search(
@OptionalParam(name=Patient.SP_IDENTIFIER) TokenAndListParam theIdentifiers
) {
ourLastMethod = "search";
ourIdentifiers = theIdentifiers;
ArrayList<Patient> retVal = new ArrayList<Patient>();
retVal.add((Patient) new Patient().addName(new HumanName().addFamily("FAMILY")).setId("1"));
return retVal;
}
//@formatter:on
}
}

View File

@ -147,6 +147,16 @@
a NullPointerException to be thrown. Now it will trigger a warning, or throw a
DataFormatException if the StrictErrorHandler is configured on the parser.
</action>
<action type="fix">
Calling a HAPI server URL with a chain on a parameter that shouldn't accept
chains (e.g.
<![CDATA[<code>GET [base]/Patient?name.foo=smith</code>]]>)
did not return an error and instead just ignored the chained part
and treated the parameter as though it did not have the chain. This
led to confusing and potentially unsafe behaviour. This has been
corrected to return an error to the client. Thanks to
Kevin Tallevi for finding this!
</action>
</release>
<release version="2.0" date="2016-08-30">
<action type="fix">