Reorganize how search param prefixes are handled and modelled based on new DSTU2 style prefixes

This commit is contained in:
jamesagnew 2016-02-15 10:05:39 -05:00
parent 23f9292b50
commit c1141eb18f
68 changed files with 1983 additions and 1251 deletions

View File

@ -10,7 +10,6 @@ import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.RestfulServer;
@SuppressWarnings(value= {"serial"})
public class ExampleProviders {
@ -35,7 +34,7 @@ public class PlainProvider {
//START SNIPPET: plainProviderServer
public class ExampleServlet extends RestfulServer {
public class ExampleServlet extends ca.uhn.fhir.rest.server.RestfulServer {
/**
* Constructor
@ -59,7 +58,7 @@ public class ExampleServlet extends RestfulServer {
//END SNIPPET: plainProviderServer
//START SNIPPET: addressStrategy
public class MyServlet extends RestfulServer {
public class MyServlet extends ca.uhn.fhir.rest.server.RestfulServer {
/**
* Constructor

View File

@ -3,7 +3,7 @@ package example;
import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
import ca.uhn.fhir.rest.server.RestfulServer;
@SuppressWarnings({ "unused", "serial" })
@SuppressWarnings({ "serial" })
//START SNIPPET: provider
public class PagingServer extends RestfulServer {

View File

@ -1,6 +1,7 @@
package example;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@ -19,7 +20,6 @@ import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.model.dstu2.resource.Conformance;
import ca.uhn.fhir.model.dstu2.resource.DiagnosticReport;
import ca.uhn.fhir.model.dstu2.resource.Observation;
@ -29,7 +29,6 @@ import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.valueset.IdentifierUseEnum;
import ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.DecimalDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.parser.DataFormatException;
@ -67,6 +66,7 @@ import ca.uhn.fhir.rest.client.api.IRestfulClient;
import ca.uhn.fhir.rest.param.CompositeParam;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
import ca.uhn.fhir.rest.param.QuantityParam;
import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.StringAndListParam;
@ -96,6 +96,8 @@ public abstract class RestfulPatientResourceProviderMore implements IResourcePro
private boolean detectedVersionConflict;
private boolean conflictHappened;
private boolean couldntFindThisId;
private FhirContext myContext;
//START SNIPPET: searchAll
@Search
public List<Organization> getAllOrganizations() {
@ -280,7 +282,7 @@ public List<Observation> findBySubject(
// Because the chained parameter "subject.identifier" is actually of type
// "token", we convert the value to a token before processing it.
TokenParam tokenSubject = subject.toTokenParam();
TokenParam tokenSubject = subject.toTokenParam(myContext);
String system = tokenSubject.getSystem();
String identifier = tokenSubject.getValue();
@ -290,7 +292,7 @@ public List<Observation> findBySubject(
// Because the chained parameter "subject.birthdate" is actually of type
// "date", we convert the value to a date before processing it.
DateParam dateSubject = subject.toDateParam();
DateParam dateSubject = subject.toDateParam(myContext);
DateTimeDt birthDate = dateSubject.getValueAsDateTimeDt();
// TODO: populate all the observations for the birthdate
@ -541,7 +543,7 @@ public List<Patient> searchByPatientAddress(
//START SNIPPET: dates
@Search()
public List<Patient> searchByObservationNames( @RequiredParam(name=Patient.SP_BIRTHDATE) DateParam theDate ) {
QuantityCompararatorEnum comparator = theDate.getComparator(); // e.g. <=
ParamPrefixEnum prefix = theDate.getPrefix(); // e.g. gt, le, etc..
Date date = theDate.getValue(); // e.g. 2011-01-02
TemporalPrecisionEnum precision = theDate.getPrecision(); // e.g. DAY
@ -554,7 +556,7 @@ public List<Patient> searchByObservationNames( @RequiredParam(name=Patient.SP_BI
public void dateClientExample() {
ITestClient client = provideTc();
//START SNIPPET: dateClient
DateParam param = new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, "2011-01-02");
DateParam param = new DateParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, "2011-01-02");
List<Patient> response = client.getPatientByDob(param);
//END SNIPPET: dateClient
}
@ -670,8 +672,8 @@ public List<Observation> getObservationsByQuantity(
List<Observation> retVal = new ArrayList<Observation>();
QuantityCompararatorEnum comparator = theQuantity.getComparator();
DecimalDt value = theQuantity.getValue();
ParamPrefixEnum prefix = theQuantity.getPrefix();
BigDecimal value = theQuantity.getValue();
String units = theQuantity.getUnits();
// .. Apply these parameters ..

View File

@ -9,7 +9,6 @@ import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
@SuppressWarnings("unused")
public abstract class ServerExceptionsExample implements IResourceProvider {
private boolean databaseIsDown;

View File

@ -11,7 +11,6 @@ import org.apache.commons.io.filefilter.WildcardFileFilter;
import org.hl7.fhir.instance.hapi.validation.DefaultProfileValidationSupport;
import org.hl7.fhir.instance.hapi.validation.FhirInstanceValidator;
import org.hl7.fhir.instance.hapi.validation.IValidationSupport;
import org.hl7.fhir.instance.hapi.validation.IValidationSupport.CodeValidationResult;
import org.hl7.fhir.instance.hapi.validation.ValidationSupportChain;
import org.hl7.fhir.instance.model.ValueSet;
import org.hl7.fhir.instance.model.ValueSet.ConceptSetComponent;
@ -96,7 +95,6 @@ public class ValidatorExamples {
}
@SuppressWarnings("unused")
public void parserValidation() {
// START SNIPPET: parserValidation
FhirContext ctx = FhirContext.forDstu2();

View File

@ -1,5 +1,6 @@
package ca.uhn.fhir.model.api;
import ca.uhn.fhir.context.FhirContext;
/*
* #%L
@ -48,11 +49,12 @@ 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
*
* @return Returns a representation of this parameter's value as it will be represented "over the wire". In other
* words, how it will be presented in a URL (although not URL escaped)
*/
public String getValueAsQueryToken();
public String getValueAsQueryToken(FhirContext theContext);
/**
* This method will return any qualifier that should be appended to the parameter name (e.g ":exact")

View File

@ -22,6 +22,7 @@ package ca.uhn.fhir.model.base.composite;
import org.apache.commons.lang3.StringUtils;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.BaseIdentifiableElement;
import ca.uhn.fhir.model.api.ICompositeDatatype;
import ca.uhn.fhir.model.api.IQueryParameterType;
@ -81,7 +82,7 @@ public abstract class BaseCodingDt extends BaseIdentifiableElement implements IC
* {@inheritDoc}
*/
@Override
public String getValueAsQueryToken() {
public String getValueAsQueryToken(FhirContext theContext) {
if (getSystemElement().getValueAsString() != null) {
return ParameterUtil.escape(StringUtils.defaultString(getSystemElement().getValueAsString())) + '|' + ParameterUtil.escape(getCodeElement().getValueAsString());
} else {

View File

@ -22,6 +22,7 @@ package ca.uhn.fhir.model.base.composite;
import org.apache.commons.lang3.StringUtils;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.BaseIdentifiableElement;
import ca.uhn.fhir.model.api.ICompositeDatatype;
import ca.uhn.fhir.model.api.IQueryParameterType;
@ -59,7 +60,7 @@ public abstract class BaseIdentifierDt extends BaseIdentifiableElement implement
* {@inheritDoc}
*/
@Override
public String getValueAsQueryToken() {
public String getValueAsQueryToken(FhirContext theContext) {
UriDt system = (UriDt) getSystemElement();
StringDt value = (StringDt) getValueElement();
if (system.getValueAsString() != null) {

View File

@ -24,6 +24,7 @@ import java.math.BigDecimal;
import org.apache.commons.lang3.StringUtils;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.BaseIdentifiableElement;
import ca.uhn.fhir.model.api.ICompositeDatatype;
import ca.uhn.fhir.model.api.IQueryParameterType;
@ -101,7 +102,7 @@ public abstract class BaseQuantityDt extends BaseIdentifiableElement implements
public abstract BoundCodeDt<?> getComparatorElement();
@Override
public String getValueAsQueryToken() {
public String getValueAsQueryToken(FhirContext theContext) {
StringBuilder b= new StringBuilder();
if (getComparatorElement() != null) {
b.append(getComparatorElement().getValue());

View File

@ -25,8 +25,13 @@ import java.util.HashMap;
import java.util.Map;
import ca.uhn.fhir.model.api.IValueSetEnumBinder;
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
import ca.uhn.fhir.util.CoverageIgnore;
/**
* @deprecated This class has been replaced by {@link ParamPrefixEnum} in HAPI FHIR 1.5
*/
@Deprecated
@CoverageIgnore
public enum QuantityCompararatorEnum {
@ -106,7 +111,7 @@ public enum QuantityCompararatorEnum {
/**
* Returns the enumerated value associated with this code
*/
public QuantityCompararatorEnum forCode(String theCode) {
public static QuantityCompararatorEnum forCode(String theCode) {
QuantityCompararatorEnum retVal = CODE_TO_ENUM.get(theCode);
return retVal;
}

View File

@ -22,6 +22,7 @@ package ca.uhn.fhir.model.primitive;
import org.apache.commons.lang3.StringUtils;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.BasePrimitive;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
@ -95,7 +96,7 @@ public class StringDt extends BasePrimitive<String> implements IQueryParameterTy
* {@inheritDoc}
*/
@Override
public String getValueAsQueryToken() {
public String getValueAsQueryToken(FhirContext theContext) {
return getValue();
}

View File

@ -449,7 +449,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
ArrayList<String> valueList = new ArrayList<String>();
String qualifier = null;
for (IQueryParameterType nextValue : nextEntry.getValue()) {
valueList.add(nextValue.getValueAsQueryToken());
valueList.add(nextValue.getValueAsQueryToken(myContext));
qualifier = nextValue.getQueryParameterQualifier();
}
qualifier = StringUtils.defaultString(qualifier);
@ -802,14 +802,14 @@ public class GenericClient extends BaseClient implements IGenericClient {
}
private static class CriterionList extends ArrayList<ICriterionInternal> {
private class CriterionList extends ArrayList<ICriterionInternal> {
private static final long serialVersionUID = 1L;
public void populateParamList(Map<String, List<String>> theParams) {
for (ICriterionInternal next : this) {
String parameterName = next.getParameterName();
String parameterValue = next.getParameterValue();
String parameterValue = next.getParameterValue(myContext);
addParam(theParams, parameterName, parameterValue);
}
}
@ -1760,11 +1760,11 @@ public class GenericClient extends BaseClient implements IGenericClient {
myCriterion.populateParamList(params);
for (TokenParam next : myTags) {
addParam(params, Constants.PARAM_TAG, next.getValueAsQueryToken());
addParam(params, Constants.PARAM_TAG, next.getValueAsQueryToken(myContext));
}
for (TokenParam next : mySecurity) {
addParam(params, Constants.PARAM_SECURITY, next.getValueAsQueryToken());
addParam(params, Constants.PARAM_SECURITY, next.getValueAsQueryToken(myContext));
}
for (String next : myProfile) {
@ -1793,7 +1793,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
if (myLastUpdated != null) {
for (DateParam next : myLastUpdated.getValuesAsQueryTokens()) {
addParam(params, Constants.PARAM_LASTUPDATED, next.getValueAsQueryToken());
addParam(params, Constants.PARAM_LASTUPDATED, next.getValueAsQueryToken(myContext));
}
}

View File

@ -1,5 +1,7 @@
package ca.uhn.fhir.rest.gclient;
import ca.uhn.fhir.context.FhirContext;
/*
* #%L
* HAPI FHIR - Core Library
@ -39,7 +41,7 @@ abstract class BaseClientParam implements IParam {
}
@Override
public String getParameterValue() {
public String getParameterValue(FhirContext theContext) {
return myParameterValue;
}

View File

@ -21,6 +21,8 @@ package ca.uhn.fhir.rest.gclient;
*/
import static org.apache.commons.lang3.StringUtils.defaultString;
import ca.uhn.fhir.context.FhirContext;
public class CompositeCriterion<A extends IParam, B extends IParam> implements ICompositeWithLeft<B>, ICriterion<B>, ICriterionInternal {
private ICriterion<B> myRight;
@ -39,10 +41,10 @@ public class CompositeCriterion<A extends IParam, B extends IParam> implements I
}
@Override
public String getParameterValue() {
public String getParameterValue(FhirContext theContext) {
ICriterionInternal left = (ICriterionInternal) myLeft;
ICriterionInternal right = (ICriterionInternal) myRight;
return defaultString(left.getParameterValue()) + '$' + defaultString(right.getParameterValue());
return defaultString(left.getParameterValue(theContext)) + '$' + defaultString(right.getParameterValue(theContext));
}
@Override

View File

@ -22,6 +22,7 @@ package ca.uhn.fhir.rest.gclient;
import java.util.Date;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.model.primitive.DateTimeDt;
@ -75,7 +76,7 @@ public class DateClientParam extends BaseClientParam implements IParam {
}
@Override
public String getParameterValue() {
public String getParameterValue(FhirContext theContext) {
return myValue;
}

View File

@ -1,5 +1,7 @@
package ca.uhn.fhir.rest.gclient;
import ca.uhn.fhir.context.FhirContext;
/*
* #%L
* HAPI FHIR - Core Library
@ -22,7 +24,7 @@ package ca.uhn.fhir.rest.gclient;
public interface ICriterionInternal {
String getParameterValue();
String getParameterValue(FhirContext theContext);
String getParameterName();

View File

@ -77,8 +77,7 @@ public interface IQuery<T> extends IClientExecutable<IQuery<T>, T>, IBaseQuery<I
/**
* Match only resources where the resource has the given profile declaration. This parameter corresponds to
* the <code>_profile</code> URL parameter.
* @param theSystem The tag code system, or <code>null</code> to match any code system (this may not be supported on all servers)
* @param theCode The tag code. Must not be <code>null</code> or empty.
* @param theProfileUri The URI of a given profile to search for resources which match
*/
IQuery<T> withProfile(String theProfileUri);

View File

@ -1,5 +1,7 @@
package ca.uhn.fhir.rest.gclient;
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
/*
* #%L
* HAPI FHIR - Core Library
@ -54,12 +56,12 @@ public class NumberClientParam extends BaseClientParam implements IParam {
return new IMatches<ICriterion<NumberClientParam>>() {
@Override
public ICriterion<NumberClientParam> number(long theNumber) {
return new StringCriterion<NumberClientParam>(getParamName(), ">" + Long.toString(theNumber));
return new StringCriterion<NumberClientParam>(getParamName(), ParamPrefixEnum.GREATERTHAN, Long.toString(theNumber));
}
@Override
public ICriterion<NumberClientParam> number(String theNumber) {
return new StringCriterion<NumberClientParam>(getParamName(), ">" + (theNumber));
return new StringCriterion<NumberClientParam>(getParamName(), ParamPrefixEnum.GREATERTHAN, (theNumber));
}
};
}
@ -68,12 +70,12 @@ public class NumberClientParam extends BaseClientParam implements IParam {
return new IMatches<ICriterion<NumberClientParam>>() {
@Override
public ICriterion<NumberClientParam> number(long theNumber) {
return new StringCriterion<NumberClientParam>(getParamName(), ">=" + Long.toString(theNumber));
return new StringCriterion<NumberClientParam>(getParamName(), ParamPrefixEnum.GREATERTHAN_OR_EQUALS, Long.toString(theNumber));
}
@Override
public ICriterion<NumberClientParam> number(String theNumber) {
return new StringCriterion<NumberClientParam>(getParamName(), ">=" + (theNumber));
return new StringCriterion<NumberClientParam>(getParamName(), ParamPrefixEnum.GREATERTHAN_OR_EQUALS, (theNumber));
}
};
}
@ -82,12 +84,12 @@ public class NumberClientParam extends BaseClientParam implements IParam {
return new IMatches<ICriterion<NumberClientParam>>() {
@Override
public ICriterion<NumberClientParam> number(long theNumber) {
return new StringCriterion<NumberClientParam>(getParamName(), "<" + Long.toString(theNumber));
return new StringCriterion<NumberClientParam>(getParamName(), ParamPrefixEnum.LESSTHAN, Long.toString(theNumber));
}
@Override
public ICriterion<NumberClientParam> number(String theNumber) {
return new StringCriterion<NumberClientParam>(getParamName(), "<" + (theNumber));
return new StringCriterion<NumberClientParam>(getParamName(), ParamPrefixEnum.LESSTHAN, (theNumber));
}
};
}
@ -96,12 +98,26 @@ public class NumberClientParam extends BaseClientParam implements IParam {
return new IMatches<ICriterion<NumberClientParam>>() {
@Override
public ICriterion<NumberClientParam> number(long theNumber) {
return new StringCriterion<NumberClientParam>(getParamName(), "<=" + Long.toString(theNumber));
return new StringCriterion<NumberClientParam>(getParamName(), ParamPrefixEnum.LESSTHAN_OR_EQUALS, Long.toString(theNumber));
}
@Override
public ICriterion<NumberClientParam> number(String theNumber) {
return new StringCriterion<NumberClientParam>(getParamName(), "<=" + (theNumber));
return new StringCriterion<NumberClientParam>(getParamName(), ParamPrefixEnum.LESSTHAN_OR_EQUALS, (theNumber));
}
};
}
public IMatches<ICriterion<NumberClientParam>> withPrefix(final ParamPrefixEnum thePrefix) {
return new IMatches<ICriterion<NumberClientParam>>() {
@Override
public ICriterion<NumberClientParam> number(long theNumber) {
return new StringCriterion<NumberClientParam>(getParamName(), thePrefix, Long.toString(theNumber));
}
@Override
public ICriterion<NumberClientParam> number(String theNumber) {
return new StringCriterion<NumberClientParam>(getParamName(), thePrefix, (theNumber));
}
};
}

View File

@ -23,10 +23,12 @@ import static org.apache.commons.lang3.StringUtils.defaultString;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.rest.gclient.NumberClientParam.IMatches;
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
/**
* Token parameter type for use in fluent client interfaces
*/
@SuppressWarnings("deprecation")
public class QuantityClientParam extends BaseClientParam implements IParam {
private String myParamName;
@ -39,12 +41,12 @@ public class QuantityClientParam extends BaseClientParam implements IParam {
return new NumberClientParam.IMatches<IAndUnits>() {
@Override
public IAndUnits number(long theNumber) {
return new AndUnits("~", Long.toString(theNumber));
return new AndUnits(ParamPrefixEnum.APPROXIMATE, Long.toString(theNumber));
}
@Override
public IAndUnits number(String theNumber) {
return new AndUnits("~", theNumber);
return new AndUnits(ParamPrefixEnum.APPROXIMATE, theNumber);
}
};
}
@ -53,12 +55,12 @@ public class QuantityClientParam extends BaseClientParam implements IParam {
return new NumberClientParam.IMatches<IAndUnits>() {
@Override
public IAndUnits number(long theNumber) {
return new AndUnits("", Long.toString(theNumber));
return new AndUnits(null, Long.toString(theNumber));
}
@Override
public IAndUnits number(String theNumber) {
return new AndUnits("", theNumber);
return new AndUnits(null, theNumber);
}
};
}
@ -72,12 +74,12 @@ public class QuantityClientParam extends BaseClientParam implements IParam {
return new NumberClientParam.IMatches<IAndUnits>() {
@Override
public IAndUnits number(long theNumber) {
return new AndUnits(">", Long.toString(theNumber));
return new AndUnits(ParamPrefixEnum.GREATERTHAN, Long.toString(theNumber));
}
@Override
public IAndUnits number(String theNumber) {
return new AndUnits(">", theNumber);
return new AndUnits(ParamPrefixEnum.GREATERTHAN, theNumber);
}
};
}
@ -86,12 +88,12 @@ public class QuantityClientParam extends BaseClientParam implements IParam {
return new NumberClientParam.IMatches<IAndUnits>() {
@Override
public IAndUnits number(long theNumber) {
return new AndUnits(">=", Long.toString(theNumber));
return new AndUnits(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, Long.toString(theNumber));
}
@Override
public IAndUnits number(String theNumber) {
return new AndUnits(">=", theNumber);
return new AndUnits(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, theNumber);
}
};
}
@ -100,12 +102,12 @@ public class QuantityClientParam extends BaseClientParam implements IParam {
return new NumberClientParam.IMatches<IAndUnits>() {
@Override
public IAndUnits number(long theNumber) {
return new AndUnits("<", Long.toString(theNumber));
return new AndUnits(ParamPrefixEnum.LESSTHAN, Long.toString(theNumber));
}
@Override
public IAndUnits number(String theNumber) {
return new AndUnits("<", theNumber);
return new AndUnits(ParamPrefixEnum.LESSTHAN, theNumber);
}
};
}
@ -114,27 +116,51 @@ public class QuantityClientParam extends BaseClientParam implements IParam {
return new NumberClientParam.IMatches<IAndUnits>() {
@Override
public IAndUnits number(long theNumber) {
return new AndUnits("<=", Long.toString(theNumber));
return new AndUnits(ParamPrefixEnum.LESSTHAN_OR_EQUALS, Long.toString(theNumber));
}
@Override
public IAndUnits number(String theNumber) {
return new AndUnits("<=", theNumber);
return new AndUnits(ParamPrefixEnum.LESSTHAN_OR_EQUALS, theNumber);
}
};
}
/**
* @deprecated Use {@link #withPrefix(ParamPrefixEnum)} instead, as {@link QuantityCompararatorEnum} has been deprecated
*/
@Deprecated
public IMatches<IAndUnits> withComparator(QuantityCompararatorEnum theComparator) {
final String cmp = theComparator != null ? theComparator.getCode() : "";
final String cmpString = theComparator != null ? theComparator.getCode() : "";
final ParamPrefixEnum prefix = ParamPrefixEnum.forDstu1Value(cmpString);
return new NumberClientParam.IMatches<IAndUnits>() {
@Override
public IAndUnits number(long theNumber) {
return new AndUnits(cmp, Long.toString(theNumber));
return new AndUnits(prefix, Long.toString(theNumber));
}
@Override
public IAndUnits number(String theNumber) {
return new AndUnits(cmp, theNumber);
return new AndUnits(prefix, theNumber);
}
};
}
/**
* Use the given quantity prefix
*
* @param thePrefix The prefix, or <code>null</code> for no prefix
*/
public IMatches<IAndUnits> withPrefix(final ParamPrefixEnum thePrefix) {
return new NumberClientParam.IMatches<IAndUnits>() {
@Override
public IAndUnits number(long theNumber) {
return new AndUnits(thePrefix, Long.toString(theNumber));
}
@Override
public IAndUnits number(String theNumber) {
return new AndUnits(thePrefix, theNumber);
}
};
}
@ -150,10 +176,12 @@ public class QuantityClientParam extends BaseClientParam implements IParam {
private class AndUnits implements IAndUnits {
private String myToken1;
private ParamPrefixEnum myPrefix;
private String myValue;
public AndUnits(String theComparator, String theNumber) {
myToken1 = defaultString(theComparator) + defaultString(theNumber);
public AndUnits(ParamPrefixEnum thePrefix, String theNumber) {
myPrefix = thePrefix;
myValue = theNumber;
}
@Override
@ -168,7 +196,7 @@ public class QuantityClientParam extends BaseClientParam implements IParam {
@Override
public ICriterion<QuantityClientParam> andUnits(String theSystem, String theUnits) {
return new QuantityCriterion(getParamName(), myToken1 , defaultString(theSystem) , defaultString(theUnits));
return new QuantityCriterion(getParamName(), myPrefix, myValue , defaultString(theSystem) , defaultString(theUnits));
}
}

View File

@ -1,5 +1,7 @@
package ca.uhn.fhir.rest.gclient;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
import ca.uhn.fhir.rest.param.ParameterUtil;
/*
@ -28,9 +30,11 @@ class QuantityCriterion implements ICriterion<QuantityClientParam>, ICriterionIn
private String myName;
private String mySystem;
private String myUnits;
private ParamPrefixEnum myPrefix;
public QuantityCriterion(String theParamName, String theValue, String theSystem, String theUnits) {
public QuantityCriterion(String theParamName, ParamPrefixEnum thePrefix, String theValue, String theSystem, String theUnits) {
myValue = theValue;
myPrefix = thePrefix;
myName = theParamName;
mySystem = theSystem;
myUnits = theUnits;
@ -42,8 +46,17 @@ class QuantityCriterion implements ICriterion<QuantityClientParam>, ICriterionIn
}
@Override
public String getParameterValue() {
return ParameterUtil.escape(myValue) + '|' + ParameterUtil.escape(mySystem) + '|' + ParameterUtil.escape(myUnits);
public String getParameterValue(FhirContext theContext) {
StringBuilder b = new StringBuilder();
if (myPrefix != null) {
b.append(ParameterUtil.escapeWithDefault(myPrefix.getValueForContext(theContext)));
}
b.append(ParameterUtil.escapeWithDefault(myValue));
b.append('|');
b.append(ParameterUtil.escapeWithDefault(mySystem));
b.append('|');
b.append(ParameterUtil.escapeWithDefault(myUnits));
return b.toString();
}
}

View File

@ -1,5 +1,6 @@
package ca.uhn.fhir.rest.gclient;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.primitive.IdDt;
/*
@ -72,8 +73,8 @@ public class ReferenceClientParam extends BaseClientParam implements IParam {
}
@Override
public String getParameterValue() {
return myWrappedCriterion.getParameterValue();
public String getParameterValue(FhirContext theContext) {
return myWrappedCriterion.getParameterValue(theContext);
}
}

View File

@ -4,6 +4,8 @@ import java.util.List;
import org.apache.commons.lang3.StringUtils;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
import ca.uhn.fhir.rest.param.ParameterUtil;
/*
@ -30,10 +32,17 @@ class StringCriterion<A extends IParam> implements ICriterion<A>, ICriterionInte
private String myValue;
private String myName;
private ParamPrefixEnum myPrefix;
public StringCriterion(String theName, String theValue) {
myName=theName;
myValue = ParameterUtil.escape(theValue);
myValue = ParameterUtil.escapeWithDefault(theValue);
}
public StringCriterion(String theName, ParamPrefixEnum thePrefix, String theValue) {
myName=theName;
myPrefix = thePrefix;
myValue = ParameterUtil.escapeWithDefault(theValue);
}
public StringCriterion(String theName, List<String> theValue) {
@ -57,7 +66,10 @@ class StringCriterion<A extends IParam> implements ICriterion<A>, ICriterionInte
}
@Override
public String getParameterValue() {
public String getParameterValue(FhirContext theContext) {
if (myPrefix != null) {
return myPrefix.getValueForContext(theContext) + myValue;
}
return myValue;
}

View File

@ -24,6 +24,7 @@ import java.util.List;
import org.apache.commons.lang3.StringUtils;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.base.composite.BaseIdentifierDt;
import ca.uhn.fhir.rest.param.ParameterUtil;
@ -67,7 +68,7 @@ class TokenCriterion implements ICriterion<TokenClientParam>, ICriterionInternal
}
@Override
public String getParameterValue() {
public String getParameterValue(FhirContext theContext) {
return myValue;
}

View File

@ -25,6 +25,7 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
import java.util.ArrayList;
import java.util.StringTokenizer;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IQueryParameterOr;
import ca.uhn.fhir.model.api.IQueryParameterType;
@ -42,12 +43,12 @@ public class QualifiedParamList extends ArrayList<String> {
super(theCapacity);
}
public QualifiedParamList(IQueryParameterOr<?> theNextOr) {
public QualifiedParamList(IQueryParameterOr<?> theNextOr, FhirContext theContext) {
for (IQueryParameterType next : theNextOr.getValuesAsQueryTokens()) {
if (myQualifier == null) {
myQualifier = next.getQueryParameterQualifier();
}
add(next.getValueAsQueryToken());
add(next.getValueAsQueryToken(theContext));
}
}

View File

@ -162,7 +162,7 @@ public class SearchParameter extends BaseQueryParameter {
List<IQueryParameterOr<?>> val = myParamBinder.encode(theContext, theObject);
for (IQueryParameterOr<?> nextOr : val) {
retVal.add(new QualifiedParamList(nextOr));
retVal.add(new QualifiedParamList(nextOr, theContext));
}
return retVal;

View File

@ -1,5 +1,7 @@
package ca.uhn.fhir.rest.param;
import ca.uhn.fhir.context.FhirContext;
/*
* #%L
* HAPI FHIR - Core Library
@ -48,14 +50,14 @@ abstract class BaseParam implements IQueryParameterType {
abstract String doGetQueryParameterQualifier();
abstract String doGetValueAsQueryToken();
abstract String doGetValueAsQueryToken(FhirContext theContext);
@Override
public final String getValueAsQueryToken() {
public final String getValueAsQueryToken(FhirContext theContext) {
if (myMissing != null) {
return myMissing ? Constants.PARAMQUALIFIER_MISSING_TRUE : Constants.PARAMQUALIFIER_MISSING_FALSE;
}
return doGetValueAsQueryToken();
return doGetValueAsQueryToken(theContext);
}
/**
@ -79,23 +81,5 @@ abstract class BaseParam implements IQueryParameterType {
abstract void doSetValueAsQueryToken(String theQualifier, String theValue);
static class ComposableBaseParam extends BaseParam{
@Override
String doGetQueryParameterQualifier() {
return null;
}
@Override
String doGetValueAsQueryToken() {
return null;
}
@Override
void doSetValueAsQueryToken(String theQualifier, String theValue) {
// nothing
}
}
}

View File

@ -0,0 +1,101 @@
package ca.uhn.fhir.rest.param;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.util.CoverageIgnore;
@SuppressWarnings("deprecation")
public abstract class BaseParamWithPrefix<T extends BaseParam> extends BaseParam {
private ParamPrefixEnum myPrefix;
/**
* Constructor
*/
// Default since this is internal
BaseParamWithPrefix() {
super();
}
/**
* Eg. if this is invoked with "gt2012-11-02", sets the prefix to GREATER_THAN and returns "2012-11-02"
*/
String extractPrefixAndReturnRest(String theString) {
int offset = 0;
while (true) {
if (theString.length() == offset || Character.isDigit(theString.charAt(offset))) {
break;
}
offset++;
}
String prefix = theString.substring(0, offset);
myPrefix = ParamPrefixEnum.forValue(prefix);
if (myPrefix == null) {
myPrefix = ParamPrefixEnum.forDstu1Value(prefix);
}
return theString.substring(offset);
}
/**
* @deprecated Use {@link #getPrefix() instead}
*/
@Deprecated
public QuantityCompararatorEnum getComparator() {
ParamPrefixEnum prefix = getPrefix();
if (prefix == null) {
return null;
}
return QuantityCompararatorEnum.forCode(prefix.getDstu1Value());
}
/**
* Returns the prefix used by this parameter (e.g. "<code>gt</code>", or "<code>eq</code>")
*/
public ParamPrefixEnum getPrefix() {
return myPrefix;
}
/**
* @deprecated Use {@link #setPrefix(ParamPrefixEnum)} instead
*/
@SuppressWarnings("unchecked")
@CoverageIgnore
@Deprecated
public T setComparator(QuantityCompararatorEnum theComparator) {
if (theComparator != null) {
myPrefix = ParamPrefixEnum.forDstu1Value(theComparator.getCode());
} else {
myPrefix = null;
}
return (T) this;
}
/**
* @deprecated Use {@link #setPrefix(ParamPrefixEnum)} instead
*/
@SuppressWarnings("unchecked")
@CoverageIgnore
@Deprecated
public T setComparator(String theComparator) {
if (isNotBlank(theComparator)) {
myPrefix = ParamPrefixEnum.forDstu1Value(theComparator);
} else {
myPrefix = null;
}
return (T) this;
}
/**
* Sets the prefix used by this parameter (e.g. "<code>gt</code>", or "<code>eq</code>")
*/
@SuppressWarnings("unchecked")
public T setPrefix(ParamPrefixEnum thePrefix) {
myPrefix = thePrefix;
return (T) this;
}
}

View File

@ -26,6 +26,7 @@ import java.util.List;
import org.apache.commons.lang3.Validate;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
@ -64,14 +65,14 @@ public class CompositeParam<A extends IQueryParameterType, B extends IQueryParam
}
@Override
String doGetValueAsQueryToken() {
String doGetValueAsQueryToken(FhirContext theContext) {
StringBuilder b = new StringBuilder();
if (myLeftType != null) {
b.append(myLeftType.getValueAsQueryToken());
b.append(myLeftType.getValueAsQueryToken(theContext));
}
b.append('$');
if (myRightType != null) {
b.append(myRightType.getValueAsQueryToken());
b.append(myRightType.getValueAsQueryToken(theContext));
}
return b.toString();
}

View File

@ -1,46 +1,32 @@
package ca.uhn.fhir.rest.param;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 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%
*/
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.model.api.IQueryParameterOr;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.model.primitive.DateDt;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.method.QualifiedParamList;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class DateParam extends DateTimeDt implements IQueryParameterType, IQueryParameterOr<DateParam> {
@SuppressWarnings("deprecation")
public class DateParam extends BaseParamWithPrefix<DateParam> implements IQueryParameterType , IQueryParameterOr<DateParam> {
private BaseParam myBase=new BaseParam.ComposableBaseParam();
private QuantityCompararatorEnum myComparator;
private final DateTimeDt myValue = new DateTimeDt();
/**
* Constructor
@ -51,41 +37,102 @@ public class DateParam extends DateTimeDt implements IQueryParameterType, IQuery
/**
* Constructor
*/
public DateParam(QuantityCompararatorEnum theComparator, Date theDate) {
myComparator = theComparator;
public DateParam(ParamPrefixEnum thePrefix, Date theDate) {
setPrefix(thePrefix);
setValue(theDate);
}
/**
* Constructor
*/
public DateParam(QuantityCompararatorEnum theComparator, DateTimeDt theDate) {
myComparator = theComparator;
setValueAsString(theDate != null ? theDate.getValueAsString() : null);
public DateParam(ParamPrefixEnum thePrefix, DateTimeDt theDate) {
setPrefix(thePrefix);
myValue.setValueAsString(theDate != null ? theDate.getValueAsString() : null);
}
/**
* Constructor
*/
public DateParam(QuantityCompararatorEnum theComparator, IPrimitiveType<Date> theDate) {
myComparator = theComparator;
setValueAsString(theDate != null ? theDate.getValueAsString() : null);
public DateParam(ParamPrefixEnum thePrefix, IPrimitiveType<Date> theDate) {
setPrefix(thePrefix);
myValue.setValueAsString(theDate != null ? theDate.getValueAsString() : null);
}
/**
* Constructor
*/
public DateParam(QuantityCompararatorEnum theComparator, long theDate) {
public DateParam(ParamPrefixEnum thePrefix, long theDate) {
Validate.inclusiveBetween(1, Long.MAX_VALUE, theDate, "theDate must not be 0 or negative");
myComparator = theComparator;
setPrefix(thePrefix);
setValue(new Date(theDate));
}
/**
* Constructor
*/
public DateParam(ParamPrefixEnum thePrefix, String theDate) {
setPrefix(thePrefix);
setValueAsString(theDate);
}
/**
* Constructor
*
* @deprecated Use constructors with {@link ParamPrefixEnum} parameter instead, as {@link QuantityCompararatorEnum}
* is deprecated
*/
@Deprecated
public DateParam(QuantityCompararatorEnum theComparator, Date theDate) {
setPrefix(toPrefix(theComparator));
setValue(theDate);
}
/**
* Constructor
*
* @deprecated Use constructors with {@link ParamPrefixEnum} parameter instead, as {@link QuantityCompararatorEnum}
* is deprecated
*/
@Deprecated
public DateParam(QuantityCompararatorEnum theComparator, DateTimeDt theDate) {
setPrefix(toPrefix(theComparator));
setValue(theDate);
}
/**
* Constructor
*
* @deprecated Use constructors with {@link ParamPrefixEnum} parameter instead, as {@link QuantityCompararatorEnum}
* is deprecated
*/
@Deprecated
public DateParam(QuantityCompararatorEnum theComparator, IPrimitiveType<Date> theDate) {
setPrefix(toPrefix(theComparator));
setValue(theDate);
}
/**
* Constructor
*
* @deprecated Use constructors with {@link ParamPrefixEnum} parameter instead, as {@link QuantityCompararatorEnum}
* is deprecated
*/
@Deprecated
public DateParam(QuantityCompararatorEnum theComparator, long theDate) {
Validate.inclusiveBetween(1, Long.MAX_VALUE, theDate, "theDate must not be 0 or negative");
setPrefix(toPrefix(theComparator));
setValue(new Date(theDate));
}
/**
* Constructor
*
* @deprecated Use constructors with {@link ParamPrefixEnum} parameter instead, as {@link QuantityCompararatorEnum}
* is deprecated
*/
@Deprecated
public DateParam(QuantityCompararatorEnum theComparator, String theDate) {
myComparator = theComparator;
setPrefix(toPrefix(theComparator));
setValueAsString(theDate);
}
@ -93,123 +140,135 @@ public class DateParam extends DateTimeDt implements IQueryParameterType, IQuery
* Constructor which takes a complete [qualifier]{date} string.
*
* @param theString
* The string
* The string
*/
public DateParam(String theString) {
setValueAsQueryToken(null, theString);
}
/**
* Returns the comparator, or <code>null</code> if none has been set
*/
public QuantityCompararatorEnum getComparator() {
return myComparator;
@Override
String doGetQueryParameterQualifier() {
return null;
}
@Override
public Boolean getMissing() {
return myBase.getMissing();
String doGetValueAsQueryToken(FhirContext theContext) {
StringBuilder b = new StringBuilder();
if (getPrefix() != null) {
b.append(ParameterUtil.escapeWithDefault(getPrefix().getValueForContext(theContext)));
}
if (myValue != null) {
b.append(ParameterUtil.escapeWithDefault(myValue.getValueAsString()));
}
return b.toString();
}
@Override
public String getQueryParameterQualifier() {
if (myBase.getMissing()!=null) {
return myBase.getQueryParameterQualifier();
void doSetValueAsQueryToken(String theQualifier, String theValue) {
setValueAsString(theValue);
}
public TemporalPrecisionEnum getPrecision() {
if (myValue != null) {
return myValue.getPrecision();
}
return null;
}
public Date getValue() {
if (myValue != null) {
return myValue.getValue();
}
return null;
}
public DateTimeDt getValueAsDateTimeDt() {
return new DateTimeDt(getValueAsString());
if (myValue == null) {
return null;
}
return new DateTimeDt(myValue.getValue());
}
public InstantDt getValueAsInstantDt() {
return new InstantDt(getValue());
if (myValue == null) {
return null;
}
return new InstantDt(myValue.getValue());
}
@Override
public String getValueAsQueryToken() {
if (myBase.getMissing()!=null) {
return myBase.getValueAsQueryToken();
public String getValueAsString() {
if (myValue != null) {
return myValue.getValueAsString();
} else {
return null;
}
if (myComparator != null && getValue() != null) {
return myComparator.getCode() + getValueAsString();
} else if (myComparator == null && getValue() != null) {
return getValueAsString();
}
return "";
}
@Override
public List<DateParam> getValuesAsQueryTokens() {
return Collections.singletonList(this);
}
/**
* Returns <code>true</code> if no date/time is specified. Note that this method does not check the comparator, so a
* QualifiedDateParam with only a comparator and no date/time is considered empty.
*/
@Override
public boolean isEmpty() {
// Just here to provide a javadoc
return super.isEmpty();
return myValue.isEmpty();
}
public void setComparator(QuantityCompararatorEnum theComparator) {
myComparator = theComparator;
}
@Override
public void setMissing(Boolean theMissing) {
myBase.setMissing(theMissing);
}
@Override
/**
* Sets the value of the param to the given date (sets to the {@link TemporalPrecisionEnum#MILLI millisecond}
* precision, and will be encoded using the system local time zone).
*/
public DateParam setValue(Date theValue) {
super.setValue(theValue, TemporalPrecisionEnum.MILLI);
myValue.setValue(theValue, TemporalPrecisionEnum.MILLI);
return this;
}
@Override
public void setValueAsQueryToken(String theQualifier, String theValue) {
myBase.setValueAsQueryToken(theQualifier, theValue);
if (myBase.getMissing()!=null) {
setValue(null);
myComparator=null;
return;
}
if (theValue.length() < 2) {
throw new DataFormatException("Invalid qualified date parameter: " + theValue);
}
char char0 = theValue.charAt(0);
char char1 = theValue.charAt(1);
if (Character.isDigit(char0)) {
setValueAsString(theValue);
/**
* Sets the value using a FHIR Date type, such as a {@link DateDt}, or a DateTimeType.
*/
public void setValue(IPrimitiveType<Date> theValue) {
if (theValue != null) {
myValue.setValueAsString(theValue.getValueAsString());
} else {
int dateStart = 2;
if (Character.isDigit(char1)) {
dateStart = 1;
}
String comparatorString = theValue.substring(0, dateStart);
QuantityCompararatorEnum comparator = QuantityCompararatorEnum.VALUESET_BINDER.fromCodeString(comparatorString);
if (comparator == null) {
throw new DataFormatException("Invalid date qualifier: " + comparatorString);
}
String dateString = theValue.substring(dateStart);
setValueAsString(dateString);
setComparator(comparator);
myValue.setValue(null);
}
}
/**
* Accepts values with or without a prefix (e.g. <code>gt2011-01-01</code> and <code>2011-01-01</code>).
* If no prefix is provided in the given value, the {@link #getPrefix() existing prefix} is preserved
*/
public void setValueAsString(String theDate) {
if (isNotBlank(theDate)) {
ParamPrefixEnum existingPrefix = getPrefix();
myValue.setValueAsString(super.extractPrefixAndReturnRest(theDate));
if (getPrefix() == null) {
setPrefix(existingPrefix);
}
} else {
myValue.setValue(null);
}
}
private ParamPrefixEnum toPrefix(QuantityCompararatorEnum theComparator) {
if (theComparator != null) {
return ParamPrefixEnum.forDstu1Value(theComparator.getCode());
}
return null;
}
@Override
public String toString() {
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
b.append("prefix", getPrefix());
b.append("value", getValueAsString());
return b.build();
}
@Override
public void setValuesAsQueryTokens(QualifiedParamList theParameters) {
myBase.setMissing(null);
myComparator = null;
setMissing(null);
setPrefix(null);
setValueAsString(null);
if (theParameters.size() == 1) {
@ -221,19 +280,9 @@ public class DateParam extends DateTimeDt implements IQueryParameterType, IQuery
}
@Override
public String toString() {
StringBuilder b = new StringBuilder();
b.append(getClass().getSimpleName());
b.append("[");
if (myComparator!=null) {
b.append(myComparator.getCode());
}
b.append(getValueAsString());
if (myBase.getMissing()!=null) {
b.append(" missing=").append(myBase.getMissing());
}
b.append("]");
return b.toString();
public List<DateParam> getValuesAsQueryTokens() {
return Collections.singletonList(this);
}
}

View File

@ -27,7 +27,6 @@ import java.util.List;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import ca.uhn.fhir.model.api.IQueryParameterAnd;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.method.QualifiedParamList;
@ -50,11 +49,13 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
* Constructor which takes two Dates representing the lower and upper bounds of the range (inclusive on both ends)
*
* @param theLowerBound
* A qualified date param representing the lower date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* A qualified date param representing the lower date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
* theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* @param theUpperBound
* A qualified date param representing the upper date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* A qualified date param representing the upper date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
* theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
*/
public DateRangeParam(Date theLowerBound, Date theUpperBound) {
setRangeFromDatesInclusive(theLowerBound, theUpperBound);
@ -62,8 +63,8 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
/**
* Sets the range from a single date param. If theDateParam has no qualifier, treats it as the lower and upper bound
* (e.g. 2011-01-02 would match any time on that day). If theDateParam has a qualifier, treats it as either the
* lower or upper bound, with no opposite bound.
* (e.g. 2011-01-02 would match any time on that day). If theDateParam has a qualifier, treats it as either the lower
* or upper bound, with no opposite bound.
*/
public DateRangeParam(DateParam theDateParam) {
if (theDateParam == null) {
@ -72,15 +73,17 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
if (theDateParam.isEmpty()) {
throw new IllegalArgumentException("theDateParam can not be empty");
}
if (theDateParam.getComparator() == null) {
if (theDateParam.getPrefix() == null) {
setRangeFromDatesInclusive(theDateParam.getValueAsString(), theDateParam.getValueAsString());
} else {
switch (theDateParam.getComparator()) {
switch (theDateParam.getPrefix()) {
case STARTS_AFTER:
case GREATERTHAN:
case GREATERTHAN_OR_EQUALS:
myLowerBound = theDateParam;
myUpperBound = null;
break;
case ENDS_BEFORE:
case LESSTHAN:
case LESSTHAN_OR_EQUALS:
myLowerBound = null;
@ -88,7 +91,7 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
break;
default:
// Should not happen
throw new IllegalStateException("Unknown comparator:" + theDateParam.getComparator() + ". This is a bug.");
throw new InvalidRequestException("Invalid comparator for date range parameter:" + theDateParam.getPrefix() + ". This is a bug.");
}
}
validateAndThrowDataFormatExceptionIfInvalid();
@ -98,13 +101,15 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
* Constructor which takes two Dates representing the lower and upper bounds of the range (inclusive on both ends)
*
* @param theLowerBound
* A qualified date param representing the lower date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* A qualified date param representing the lower date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
* theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* @param theUpperBound
* A qualified date param representing the upper date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* A qualified date param representing the upper date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
* theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
*/
public DateRangeParam(DateTimeDt theLowerBound, DateTimeDt theUpperBound) {
public DateRangeParam(DateParam theLowerBound, DateParam theUpperBound) {
setRangeFromDatesInclusive(theLowerBound, theUpperBound);
}
@ -112,11 +117,13 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
* Constructor which takes two Dates representing the lower and upper bounds of the range (inclusive on both ends)
*
* @param theLowerBound
* A qualified date param representing the lower date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* A qualified date param representing the lower date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
* theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* @param theUpperBound
* A qualified date param representing the upper date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* A qualified date param representing the upper date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
* theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
*/
public DateRangeParam(IPrimitiveType<Date> theLowerBound, IPrimitiveType<Date> theUpperBound) {
setRangeFromDatesInclusive(theLowerBound, theUpperBound);
@ -126,28 +133,30 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
* Constructor which takes two strings representing the lower and upper bounds of the range (inclusive on both ends)
*
* @param theLowerBound
* An unqualified date param representing the lower date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Either theLowerBound or theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* An unqualified date param representing the lower date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Either theLowerBound or theUpperBound may both be populated, or
* one may be null, but it is not valid for both to be null.
* @param theUpperBound
* An unqualified date param representing the upper date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Either theLowerBound or theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* An unqualified date param representing the upper date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Either theLowerBound or theUpperBound may both be populated, or
* one may be null, but it is not valid for both to be null.
*/
public DateRangeParam(String theLowerBound, String theUpperBound) {
setRangeFromDatesInclusive(theLowerBound, theUpperBound);
}
private void addParam(DateParam theParsed) throws InvalidRequestException {
if (theParsed.getComparator() == null) {
if (theParsed.getPrefix() == null) {
if (myLowerBound != null || myUpperBound != null) {
throw new InvalidRequestException("Can not have multiple date range parameters for the same param without a qualifier");
}
myLowerBound = new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, theParsed.getValueAsString());
myUpperBound = new DateParam(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS, theParsed.getValueAsString());
myLowerBound = new DateParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, theParsed.getValueAsString());
myUpperBound = new DateParam(ParamPrefixEnum.LESSTHAN_OR_EQUALS, theParsed.getValueAsString());
} else {
switch (theParsed.getComparator()) {
switch (theParsed.getPrefix()) {
case GREATERTHAN:
case GREATERTHAN_OR_EQUALS:
if (myLowerBound != null) {
@ -163,7 +172,7 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
myUpperBound = theParsed;
break;
default:
throw new InvalidRequestException("Unknown comparator: " + theParsed.getComparator());
throw new InvalidRequestException("Unknown comparator: " + theParsed.getPrefix());
}
}
@ -178,8 +187,8 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
return null;
}
Date retVal = myLowerBound.getValue();
if (myLowerBound.getComparator() != null) {
switch (myLowerBound.getComparator()) {
if (myLowerBound.getPrefix() != null) {
switch (myLowerBound.getPrefix()) {
case GREATERTHAN:
retVal = myLowerBound.getPrecision().add(retVal, 1);
break;
@ -187,7 +196,7 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
break;
case LESSTHAN:
case LESSTHAN_OR_EQUALS:
throw new IllegalStateException("Unvalid lower bound comparator: " + myLowerBound.getComparator());
throw new IllegalStateException("Unvalid lower bound comparator: " + myLowerBound.getPrefix());
}
}
return retVal;
@ -202,8 +211,8 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
return null;
}
Date retVal = myUpperBound.getValue();
if (myUpperBound.getComparator() != null) {
switch (myUpperBound.getComparator()) {
if (myUpperBound.getPrefix() != null) {
switch (myUpperBound.getPrefix()) {
case LESSTHAN:
retVal = new Date(retVal.getTime() - 1L);
break;
@ -213,7 +222,7 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
break;
case GREATERTHAN_OR_EQUALS:
case GREATERTHAN:
throw new IllegalStateException("Unvalid upper bound comparator: " + myUpperBound.getComparator());
throw new IllegalStateException("Unvalid upper bound comparator: " + myUpperBound.getPrefix());
}
}
return retVal;
@ -252,15 +261,17 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
* Sets the range from a pair of dates, inclusive on both ends
*
* @param theLowerBound
* A qualified date param representing the lower date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* A qualified date param representing the lower date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
* theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* @param theUpperBound
* A qualified date param representing the upper date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* A qualified date param representing the upper date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
* theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
*/
public void setRangeFromDatesInclusive(Date theLowerBound, Date theUpperBound) {
myLowerBound = theLowerBound != null ? new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, theLowerBound) : null;
myUpperBound = theUpperBound != null ? new DateParam(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS, theUpperBound) : null;
myLowerBound = theLowerBound != null ? new DateParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, theLowerBound) : null;
myUpperBound = theUpperBound != null ? new DateParam(ParamPrefixEnum.LESSTHAN_OR_EQUALS, theUpperBound) : null;
validateAndThrowDataFormatExceptionIfInvalid();
}
@ -268,23 +279,17 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
* Sets the range from a pair of dates, inclusive on both ends
*
* @param theLowerBound
* A qualified date param representing the lower date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* A qualified date param representing the lower date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
* theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* @param theUpperBound
* A qualified date param representing the upper date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* A qualified date param representing the upper date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
* theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
*/
public void setRangeFromDatesInclusive(DateTimeDt theLowerBound, DateTimeDt theUpperBound) {
if (theLowerBound instanceof DateParam) {
myLowerBound = (DateParam) theLowerBound;
} else {
myLowerBound = theLowerBound != null ? new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, theLowerBound) : null;
}
if (theUpperBound instanceof DateParam) {
myUpperBound = (DateParam) theUpperBound;
} else {
myUpperBound = theUpperBound != null ? new DateParam(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS, theUpperBound) : null;
}
public void setRangeFromDatesInclusive(DateParam theLowerBound, DateParam theUpperBound) {
myLowerBound = theLowerBound;
myUpperBound = theUpperBound;
validateAndThrowDataFormatExceptionIfInvalid();
}
@ -292,30 +297,35 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
* Sets the range from a pair of dates, inclusive on both ends
*
* @param theLowerBound
* A qualified date param representing the lower date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* A qualified date param representing the lower date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
* theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* @param theUpperBound
* A qualified date param representing the upper date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* A qualified date param representing the upper date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
* theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
*/
public void setRangeFromDatesInclusive(IPrimitiveType<Date> theLowerBound, IPrimitiveType<Date> theUpperBound) {
myLowerBound = theLowerBound != null ? new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, theLowerBound) : null;
myUpperBound = theUpperBound != null ? new DateParam(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS, theUpperBound) : null;
myLowerBound = theLowerBound != null ? new DateParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, theLowerBound) : null;
myUpperBound = theUpperBound != null ? new DateParam(ParamPrefixEnum.LESSTHAN_OR_EQUALS, theUpperBound) : null;
validateAndThrowDataFormatExceptionIfInvalid();
}
/**
* Sets the range from a pair of dates, inclusive on both ends
*
* @param theLowerBound
* A qualified date param representing the lower date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* A qualified date param representing the lower date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
* theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* @param theUpperBound
* A qualified date param representing the upper date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
* A qualified date param representing the upper date bound (optionally may include time), e.g.
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
* theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
*/
public void setRangeFromDatesInclusive(String theLowerBound, String theUpperBound) {
myLowerBound = theLowerBound != null ? new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, theLowerBound) : null;
myUpperBound = theUpperBound != null ? new DateParam(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS, theUpperBound) : null;
myLowerBound = theLowerBound != null ? new DateParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, theLowerBound) : null;
myUpperBound = theUpperBound != null ? new DateParam(ParamPrefixEnum.LESSTHAN_OR_EQUALS, theUpperBound) : null;
validateAndThrowDataFormatExceptionIfInvalid();
}
@ -326,7 +336,7 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
@Override
public void setValuesAsQueryTokens(List<QualifiedParamList> theParameters) throws InvalidRequestException {
boolean haveHadUnqualifiedParameter = false;
for (QualifiedParamList paramList : theParameters) {
if (paramList.size() == 0) {
@ -339,16 +349,16 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
DateParam parsed = new DateParam();
parsed.setValueAsQueryToken(paramList.getQualifier(), param);
addParam(parsed);
if (parsed.getComparator() == null) {
if (parsed.getPrefix() == null) {
if (haveHadUnqualifiedParameter) {
throw new InvalidRequestException("Multiple date parameters with the same name and no qualifier (>, <, etc.) is not supported");
throw new InvalidRequestException("Multiple date parameters with the same name and no qualifier (>, <, etc.) is not supported");
}
haveHadUnqualifiedParameter=true;
haveHadUnqualifiedParameter = true;
}
}
}
@Override
@ -357,17 +367,17 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
b.append(getClass().getSimpleName());
b.append("[");
if (haveLowerBound()) {
if (myLowerBound.getComparator() != null) {
b.append(myLowerBound.getComparator().getCode());
if (myLowerBound.getPrefix() != null) {
b.append(myLowerBound.getPrefix().getValue());
}
b.append(myLowerBound.getValueAsString());
}
if (haveUpperBound()) {
if(haveLowerBound()) {
if (haveLowerBound()) {
b.append(" ");
}
if (myUpperBound.getComparator() != null) {
b.append(myUpperBound.getComparator().getCode());
if (myUpperBound.getPrefix() != null) {
b.append(myUpperBound.getPrefix().getValue());
}
b.append(myUpperBound.getValueAsString());
} else {
@ -394,32 +404,32 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
}
if (haveLowerBound) {
if (myLowerBound.getComparator() == null) {
myLowerBound.setComparator(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS);
if (myLowerBound.getPrefix() == null) {
myLowerBound.setPrefix(ParamPrefixEnum.GREATERTHAN_OR_EQUALS);
}
switch (myLowerBound.getComparator()) {
switch (myLowerBound.getPrefix()) {
case GREATERTHAN:
case GREATERTHAN_OR_EQUALS:
default:
break;
case LESSTHAN:
case LESSTHAN_OR_EQUALS:
throw new DataFormatException("Lower bound comparator must be > or >=, can not be " + myLowerBound.getComparator().getCode());
throw new DataFormatException("Lower bound comparator must be > or >=, can not be " + myLowerBound.getPrefix().getValue());
}
}
if (haveUpperBound) {
if (myUpperBound.getComparator() == null) {
myUpperBound.setComparator(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS);
if (myUpperBound.getPrefix() == null) {
myUpperBound.setPrefix(ParamPrefixEnum.LESSTHAN_OR_EQUALS);
}
switch (myUpperBound.getComparator()) {
switch (myUpperBound.getPrefix()) {
case LESSTHAN:
case LESSTHAN_OR_EQUALS:
default:
break;
case GREATERTHAN:
case GREATERTHAN_OR_EQUALS:
throw new DataFormatException("Upper bound comparator must be < or <=, can not be " + myUpperBound.getComparator().getCode());
throw new DataFormatException("Upper bound comparator must be < or <=, can not be " + myUpperBound.getPrefix().getValue());
}
}

View File

@ -1,369 +0,0 @@
package ca.uhn.fhir.rest.param;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 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%
*/
import java.util.List;
import ca.uhn.fhir.model.api.ICompositeDatatype;
import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.SimpleSetter;
import ca.uhn.fhir.model.base.composite.BaseQuantityDt;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.model.primitive.BoundCodeDt;
import ca.uhn.fhir.model.primitive.CodeDt;
import ca.uhn.fhir.model.primitive.DecimalDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.UriDt;
/**
* Base class for QuantityDt of any version
*/
class InternalQuantityDt extends BaseQuantityDt implements ICompositeDatatype {
/**
* Constructor
*/
public InternalQuantityDt() {
// nothing
}
/**
* Constructor
*/
@SimpleSetter
public InternalQuantityDt(@SimpleSetter.Parameter(name = "theValue") double theValue) {
setValue(theValue);
}
/**
* Constructor
*/
@SimpleSetter
public InternalQuantityDt(@SimpleSetter.Parameter(name = "theValue") long theValue) {
setValue(theValue);
}
/**
* Constructor
*/
@SimpleSetter
public InternalQuantityDt(@SimpleSetter.Parameter(name = "theComparator") QuantityCompararatorEnum theComparator, @SimpleSetter.Parameter(name = "theValue") double theValue,
@SimpleSetter.Parameter(name = "theUnits") String theUnits) {
setValue(theValue);
setComparator(theComparator);
setUnits(theUnits);
}
/**
* Constructor
*/
@SimpleSetter
public InternalQuantityDt(@SimpleSetter.Parameter(name = "theComparator") QuantityCompararatorEnum theComparator, @SimpleSetter.Parameter(name = "theValue") long theValue,
@SimpleSetter.Parameter(name = "theUnits") String theUnits) {
setValue(theValue);
setComparator(theComparator);
setUnits(theUnits);
}
/**
* Constructor
*/
@SimpleSetter
public InternalQuantityDt(@SimpleSetter.Parameter(name = "theComparator") QuantityCompararatorEnum theComparator, @SimpleSetter.Parameter(name = "theValue") double theValue,
@SimpleSetter.Parameter(name = "theSystem") String theSystem, @SimpleSetter.Parameter(name = "theUnits") String theUnits) {
setValue(theValue);
setComparator(theComparator);
setSystem(theSystem);
setUnits(theUnits);
}
/**
* Constructor
*/
@SimpleSetter
public InternalQuantityDt(@SimpleSetter.Parameter(name = "theComparator") QuantityCompararatorEnum theComparator, @SimpleSetter.Parameter(name = "theValue") long theValue,
@SimpleSetter.Parameter(name = "theSystem") String theSystem, @SimpleSetter.Parameter(name = "theUnits") String theUnits) {
setValue(theValue);
setComparator(theComparator);
setSystem(theSystem);
setUnits(theUnits);
}
@Child(name = "value", type = DecimalDt.class, order = 0, min = 0, max = 1)
@Description(shortDefinition = "Numerical value (with implicit precision)", formalDefinition = "The value of the measured amount. The value includes an implicit precision in the presentation of the value")
private DecimalDt myValue;
@Child(name = "comparator", type = CodeDt.class, order = 1, min = 0, max = 1)
@Description(shortDefinition = "< | <= | >= | > - how to understand the value", formalDefinition = "How the value should be understood and represented - whether the actual value is greater or less than the stated value due to measurement issues. E.g. if the comparator is \"<\" , then the real value is < stated value")
private BoundCodeDt<QuantityCompararatorEnum> myComparator;
@Child(name = "units", type = StringDt.class, order = 2, min = 0, max = 1)
@Description(shortDefinition = "Unit representation", formalDefinition = "A human-readable form of the units")
private StringDt myUnits;
@Child(name = "system", type = UriDt.class, order = 3, min = 0, max = 1)
@Description(shortDefinition = "System that defines coded unit form", formalDefinition = "The identification of the system that provides the coded form of the unit")
private UriDt mySystem;
@Child(name = "code", type = CodeDt.class, order = 4, min = 0, max = 1)
@Description(shortDefinition = "Coded form of the unit", formalDefinition = "A computer processable form of the units in some unit representation system")
private CodeDt myCode;
@Override
public boolean isEmpty() {
return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty(myValue, myComparator, myUnits, mySystem, myCode);
}
@Override
public <T extends IElement> List<T> getAllPopulatedChildElementsOfType(Class<T> theType) {
return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myValue, myComparator, myUnits, mySystem, myCode);
}
/**
* Gets the value(s) for <b>value</b> (Numerical value (with implicit precision)). creating it if it does not exist. Will not return <code>null</code>.
*
* <p>
* <b>Definition:</b> The value of the measured amount. The value includes an implicit precision in the presentation of the value
* </p>
*/
public DecimalDt getValueElement() {
if (myValue == null) {
myValue = new DecimalDt();
}
return myValue;
}
/**
* Sets the value(s) for <b>value</b> (Numerical value (with implicit precision))
*
* <p>
* <b>Definition:</b> The value of the measured amount. The value includes an implicit precision in the presentation of the value
* </p>
*/
public InternalQuantityDt setValue(DecimalDt theValue) {
myValue = theValue;
return this;
}
/**
* Sets the value for <b>value</b> (Numerical value (with implicit precision))
*
* <p>
* <b>Definition:</b> The value of the measured amount. The value includes an implicit precision in the presentation of the value
* </p>
*/
public InternalQuantityDt setValue(long theValue) {
myValue = new DecimalDt(theValue);
return this;
}
/**
* Sets the value for <b>value</b> (Numerical value (with implicit precision))
*
* <p>
* <b>Definition:</b> The value of the measured amount. The value includes an implicit precision in the presentation of the value
* </p>
*/
public InternalQuantityDt setValue(double theValue) {
myValue = new DecimalDt(theValue);
return this;
}
/**
* Sets the value for <b>value</b> (Numerical value (with implicit precision))
*
* <p>
* <b>Definition:</b> The value of the measured amount. The value includes an implicit precision in the presentation of the value
* </p>
*/
public InternalQuantityDt setValue(java.math.BigDecimal theValue) {
myValue = new DecimalDt(theValue);
return this;
}
/**
* Gets the value(s) for <b>comparator</b> (< | <= | >= | > - how to understand the value). creating it if it does not exist. Will not return <code>null</code>.
*
* <p>
* <b>Definition:</b> How the value should be understood and represented - whether the actual value is greater or less than the stated value due to measurement issues. E.g. if the comparator is
* \"<\" , then the real value is < stated value
* </p>
*/
public BoundCodeDt<QuantityCompararatorEnum> getComparatorElement() {
if (myComparator == null) {
myComparator = new BoundCodeDt<QuantityCompararatorEnum>(QuantityCompararatorEnum.VALUESET_BINDER);
}
return myComparator;
}
/**
* Sets the value(s) for <b>comparator</b> (< | <= | >= | > - how to understand the value)
*
* <p>
* <b>Definition:</b> How the value should be understood and represented - whether the actual value is greater or less than the stated value due to measurement issues. E.g. if the comparator is
* \"<\" , then the real value is < stated value
* </p>
*/
public InternalQuantityDt setComparator(BoundCodeDt<QuantityCompararatorEnum> theValue) {
myComparator = theValue;
return this;
}
/**
* Sets the value(s) for <b>comparator</b> (< | <= | >= | > - how to understand the value)
*
* <p>
* <b>Definition:</b> How the value should be understood and represented - whether the actual value is greater or less than the stated value due to measurement issues. E.g. if the comparator is
* \"<\" , then the real value is < stated value
* </p>
*/
public InternalQuantityDt setComparator(QuantityCompararatorEnum theValue) {
getComparatorElement().setValueAsEnum(theValue);
return this;
}
/**
* Gets the value(s) for <b>units</b> (Unit representation). creating it if it does not exist. Will not return <code>null</code>.
*
* <p>
* <b>Definition:</b> A human-readable form of the units
* </p>
*/
public StringDt getUnitsElement() {
if (myUnits == null) {
myUnits = new StringDt();
}
return myUnits;
}
/**
* Sets the value(s) for <b>units</b> (Unit representation)
*
* <p>
* <b>Definition:</b> A human-readable form of the units
* </p>
*/
public InternalQuantityDt setUnits(StringDt theValue) {
myUnits = theValue;
return this;
}
/**
* Sets the value for <b>units</b> (Unit representation)
*
* <p>
* <b>Definition:</b> A human-readable form of the units
* </p>
*/
public InternalQuantityDt setUnits(String theString) {
myUnits = new StringDt(theString);
return this;
}
/**
* Gets the value(s) for <b>system</b> (System that defines coded unit form). creating it if it does not exist. Will not return <code>null</code>.
*
* <p>
* <b>Definition:</b> The identification of the system that provides the coded form of the unit
* </p>
*/
public UriDt getSystemElement() {
if (mySystem == null) {
mySystem = new UriDt();
}
return mySystem;
}
/**
* Sets the value(s) for <b>system</b> (System that defines coded unit form)
*
* <p>
* <b>Definition:</b> The identification of the system that provides the coded form of the unit
* </p>
*/
public InternalQuantityDt setSystem(UriDt theValue) {
mySystem = theValue;
return this;
}
/**
* Sets the value for <b>system</b> (System that defines coded unit form)
*
* <p>
* <b>Definition:</b> The identification of the system that provides the coded form of the unit
* </p>
*/
public InternalQuantityDt setSystem(String theUri) {
mySystem = new UriDt(theUri);
return this;
}
/**
* Gets the value(s) for <b>code</b> (Coded form of the unit). creating it if it does not exist. Will not return <code>null</code>.
*
* <p>
* <b>Definition:</b> A computer processable form of the units in some unit representation system
* </p>
*/
public CodeDt getCodeElement() {
if (myCode == null) {
myCode = new CodeDt();
}
return myCode;
}
/**
* Sets the value(s) for <b>code</b> (Coded form of the unit)
*
* <p>
* <b>Definition:</b> A computer processable form of the units in some unit representation system
* </p>
*/
public InternalQuantityDt setCode(CodeDt theValue) {
myCode = theValue;
return this;
}
/**
* Sets the value for <b>code</b> (Coded form of the unit)
*
* <p>
* <b>Definition:</b> A computer processable form of the units in some unit representation system
* </p>
*/
public InternalQuantityDt setCode(String theCode) {
myCode = new CodeDt(theCode);
return this;
}
@Override
public Boolean getMissing() {
throw new UnsupportedOperationException();
}
@Override
public void setMissing(Boolean theMissing) {
throw new UnsupportedOperationException();
}
}

View File

@ -20,17 +20,26 @@ package ca.uhn.fhir.rest.param;
* #L%
*/
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.math.BigDecimal;
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;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
public class NumberParam extends BaseParam implements IQueryParameterType {
public class NumberParam extends BaseParamWithPrefix<NumberParam> implements IQueryParameterType {
private InternalQuantityDt myQuantity = new InternalQuantityDt();
private BigDecimal myQuantity;
/**
* Constructor
*/
public NumberParam() {
super();
}
/**
@ -49,10 +58,12 @@ public class NumberParam extends BaseParam implements IQueryParameterType {
}
@Override
String doGetValueAsQueryToken() {
String doGetValueAsQueryToken(FhirContext theContext) {
StringBuilder b = new StringBuilder();
b.append(ParameterUtil.escapeWithDefault(myQuantity.getComparatorElement().getValue()));
b.append(ParameterUtil.escapeWithDefault(myQuantity.getValueElement().toString()));
if (getPrefix() != null) {
b.append(ParameterUtil.escapeWithDefault(getPrefix().getValueForContext(theContext)));
}
b.append(ParameterUtil.escapeWithDefault(myQuantity.toPlainString()));
return b.toString();
}
@ -61,46 +72,29 @@ public class NumberParam extends BaseParam implements IQueryParameterType {
if (getMissing() != null && isBlank(theValue)) {
return;
}
if (theValue.startsWith("<=")) {
myQuantity.setComparator(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS);
myQuantity.setValue(new BigDecimal(theValue.substring(2)));
} else if (theValue.startsWith("<")) {
myQuantity.setComparator(QuantityCompararatorEnum.LESSTHAN);
myQuantity.setValue(new BigDecimal(theValue.substring(1)));
} else if (theValue.startsWith(">=")) {
myQuantity.setComparator(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS);
myQuantity.setValue(new BigDecimal(theValue.substring(2)));
} else if (theValue.startsWith(">")) {
myQuantity.setComparator(QuantityCompararatorEnum.GREATERTHAN);
myQuantity.setValue(new BigDecimal(theValue.substring(1)));
} else {
myQuantity.setComparator((QuantityCompararatorEnum) null);
myQuantity.setValue(new BigDecimal(theValue));
String value = super.extractPrefixAndReturnRest(theValue);
myQuantity = null;
if (isNotBlank(value)) {
myQuantity = new BigDecimal(value);
}
}
public QuantityCompararatorEnum getComparator() {
return myQuantity.getComparatorElement().getValueAsEnum();
@Override
public String toString() {
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SIMPLE_STYLE);
b.append("prefix", getPrefix());
b.append("value", myQuantity);
return b.build();
}
public BigDecimal getValue() {
return myQuantity.getValueElement().getValue();
return myQuantity;
}
@Override
public String toString() {
StringBuilder b = new StringBuilder();
b.append(getClass().getSimpleName());
b.append("[");
if (myQuantity.getComparatorElement().isEmpty() == false) {
b.append(myQuantity.getComparatorElement().getValue());
}
if (myQuantity.getValueElement().isEmpty() == false) {
b.append(myQuantity.getValueElement().toString());
}
b.append("]");
return b.toString();
public NumberParam setValue(BigDecimal theValue) {
myQuantity = theValue;
return this;
}
}

View File

@ -0,0 +1,156 @@
package ca.uhn.fhir.rest.param;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
/**
* Comparator/qualifier for values used in REST params, such as {@link DateParam}, {@link NumberParam}, and
* {@link QuantityParam}
*
* @since 1.5
*/
public enum ParamPrefixEnum {
/**
* Code Value: <b>eq</b>
*
* The actual value is equal to the given value
*/
APPROXIMATE("~", "ap"),
/**
* Code Value: <b>eb</b>
*
* The range of the search value does overlap not with the range of the target value, and the range above the search value contains the range of the target value
*/
ENDS_BEFORE("", "eb"),
/**
* Code Value: <b>eq</b>
*
* The actual value is equal to the given value
*/
EQUAL("", "eq"),
/**
* Code Value: <b>gt</b>
*
* The actual value is greater than the given value.
*/
GREATERTHAN(">", "gt"),
/**
* Code Value: <b>ge</b>
*
* The actual value is greater than or equal to the given value.
*/
GREATERTHAN_OR_EQUALS(">=", "ge"),
/**
* Code Value: <b>lt</b>
*
* The actual value is less than the given value.
*/
LESSTHAN("<", "lt"),
/**
* Code Value: <b>le</b>
*
* The actual value is less than or equal to the given value.
*/
LESSTHAN_OR_EQUALS("<=", "le"),
/**
* Code Value: <b>ne</b>
*
* The actual value is not equal to the given value
*/
NOT_EQUAL("", "ne"),
/**
* Code Value: <b>sa</b>
*
* The range of the search value does not overlap with the range of the target value, and the range below the search value contains the range of the target value
*/
STARTS_AFTER("", "sa");
private static final Map<String, ParamPrefixEnum> DSTU1_TO_PREFIX;
private static final Map<String, ParamPrefixEnum> VALUE_TO_PREFIX;
static {
HashMap<String, ParamPrefixEnum> valueToPrefix = new HashMap<String, ParamPrefixEnum>();
HashMap<String, ParamPrefixEnum> dstu1ToPrefix = new HashMap<String, ParamPrefixEnum>();
for (ParamPrefixEnum next : values()) {
valueToPrefix.put(next.getValue(), next);
if (isNotBlank(next.getDstu1Value())) {
dstu1ToPrefix.put(next.getDstu1Value(), next);
}
}
VALUE_TO_PREFIX = Collections.unmodifiableMap(valueToPrefix);
DSTU1_TO_PREFIX = Collections.unmodifiableMap(dstu1ToPrefix);
}
private final String myDstu1Value;
private final String myValue;
private ParamPrefixEnum(String theDstu1Value, String theValue) {
myDstu1Value = theDstu1Value;
myValue = theValue;
}
/**
* Returns the DSTU1 value, e.g. <code>&lt;</code> or <code>~</code>
*/
public String getDstu1Value() {
return myDstu1Value;
}
/**
* Returns the DSTU2+ value, e.g. <code>lt</code> or <code>eq</code>
*/
public String getValue() {
return myValue;
}
/**
* Returns the appropriate value for the given context, based on the
* FHIR version supported by the context
*/
public String getValueForContext(FhirContext theContext) {
if (theContext.getVersion().getVersion() == FhirVersionEnum.DSTU1) {
return getDstu1Value();
} else {
return getValue();
}
}
/**
* Returns the prefix associated with a given DSTU1 value (e.g. <code>&lt;</code> or <code>~</code>)
*
* @param theValue
* e.g. <code>&lt;</code> or <code>~</code>
* @return The prefix, or <code>null</code> if no prefix matches the value
*/
public static ParamPrefixEnum forDstu1Value(String theValue) {
return DSTU1_TO_PREFIX.get(theValue);
}
/**
* Returns the prefix associated with a given DSTU2+ value (e.g. <code>lt</code> or <code>eq</code>)
*
* @param theValue
* e.g. <code>&lt;</code> or <code>~</code>
* @return The prefix, or <code>null</code> if no prefix matches the value
*/
public static ParamPrefixEnum forValue(String theValue) {
return VALUE_TO_PREFIX.get(theValue);
}
}

View File

@ -1,51 +1,32 @@
package ca.uhn.fhir.rest.param;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 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%
*/
import static ca.uhn.fhir.rest.param.ParameterUtil.escape;
import static org.apache.commons.lang3.StringUtils.defaultString;
import java.math.BigDecimal;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.model.primitive.BoundCodeDt;
import ca.uhn.fhir.model.primitive.CodeDt;
import ca.uhn.fhir.model.primitive.DecimalDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.util.CoverageIgnore;
public class QuantityParam extends BaseParam implements IQueryParameterType {
@SuppressWarnings("deprecation")
public class QuantityParam extends BaseParamWithPrefix<QuantityParam> implements IQueryParameterType {
private boolean myApproximate;
private InternalQuantityDt myQuantity = new InternalQuantityDt();
private BigDecimal myValue;
private String mySystem;
private String myUnits;
/**
* Constructor
*/
public QuantityParam() {
super();
}
/**
@ -59,7 +40,9 @@ public class QuantityParam extends BaseParam implements IQueryParameterType {
* The unit system
* @param theUnits
* The unit code
* @deprecated Use the equivalent constructor which uses {@link ParamPrefixEnum} instead, as {@link QuantityCompararatorEnum} has been deprecated
*/
@Deprecated
public QuantityParam(QuantityCompararatorEnum theComparator, BigDecimal theValue, String theSystem, String theUnits) {
setComparator(theComparator);
setValue(theValue);
@ -78,7 +61,9 @@ public class QuantityParam extends BaseParam implements IQueryParameterType {
* The unit system
* @param theUnits
* The unit code
* @deprecated Use the equivalent constructor which uses {@link ParamPrefixEnum} instead, as {@link QuantityCompararatorEnum} has been deprecated
*/
@Deprecated
public QuantityParam(QuantityCompararatorEnum theComparator, double theValue, String theSystem, String theUnits) {
setComparator(theComparator);
setValue(theValue);
@ -97,19 +82,85 @@ public class QuantityParam extends BaseParam implements IQueryParameterType {
* The unit system
* @param theUnits
* The unit code
* @deprecated Use the equivalent constructor which uses {@link ParamPrefixEnum} instead, as {@link QuantityCompararatorEnum} has been deprecated
*/
@Deprecated
public QuantityParam(QuantityCompararatorEnum theComparator, long theValue, String theSystem, String theUnits) {
setComparator(theComparator);
setValue(theValue);
setSystem(theSystem);
setUnits(theUnits);
}
/**
* Constructor
*
* @param thePrefix
* The comparator, or <code>null</code> for an equals comparator
* @param theValue
* A quantity value
* @param theSystem
* The unit system
* @param theUnits
* The unit code
*/
public QuantityParam(ParamPrefixEnum thePrefix, BigDecimal theValue, String theSystem, String theUnits) {
setPrefix(thePrefix);
setValue(theValue);
setSystem(theSystem);
setUnits(theUnits);
}
/**
* Constructor
*
* @param thePrefix
* The comparator, or <code>null</code> for an equals comparator
* @param theValue
* A quantity value
* @param theSystem
* The unit system
* @param theUnits
* The unit code
*/
public QuantityParam(ParamPrefixEnum thePrefix, double theValue, String theSystem, String theUnits) {
setPrefix(thePrefix);
setValue(theValue);
setSystem(theSystem);
setUnits(theUnits);
}
/**
* Constructor
*
* @param thePrefix
* The comparator, or <code>null</code> for an equals comparator
* @param theValue
* A quantity value
* @param theSystem
* The unit system
* @param theUnits
* The unit code
*/
public QuantityParam(ParamPrefixEnum thePrefix, long theValue, String theSystem, String theUnits) {
setPrefix(thePrefix);
setValue(theValue);
setSystem(theSystem);
setUnits(theUnits);
}
/**
* Constructor
*
* @param theQuantity
* A quantity value (with no system or units), such as "100.0" or "&lt;=4"
* A quantity value (with no system or units), such as "100.0" or "gt4"
*/
public QuantityParam(String theQuantity) {
setValueAsQueryToken(null, theQuantity);
@ -143,12 +194,10 @@ public class QuantityParam extends BaseParam implements IQueryParameterType {
private void clear() {
setMissing(null);
myQuantity.setComparator((BoundCodeDt<QuantityCompararatorEnum>) null);
myQuantity.setCode((CodeDt) null);
myQuantity.setSystem((UriDt) null);
myQuantity.setUnits((StringDt) null);
myQuantity.setValue((DecimalDt) null);
myApproximate = false;
setPrefix(null);
setSystem((String)null);
setUnits(null);
setValue((BigDecimal)null);
}
@Override
@ -157,29 +206,28 @@ public class QuantityParam extends BaseParam implements IQueryParameterType {
}
@Override
String doGetValueAsQueryToken() {
String doGetValueAsQueryToken(FhirContext theContext) {
StringBuilder b = new StringBuilder();
if (myApproximate) {
b.append('~');
} else {
b.append(defaultString(escape(myQuantity.getComparatorElement().getValue())));
if (getPrefix() != null) {
b.append(ParameterUtil.escapeWithDefault(getPrefix().getValueForContext(theContext)));
}
if (!myQuantity.getValueElement().isEmpty()) {
b.append(defaultString(escape(myQuantity.getValueElement().getValueAsString())));
}
b.append(ParameterUtil.escapeWithDefault(getValueAsString()));
b.append('|');
if (!myQuantity.getSystemElement().isEmpty()) {
b.append(defaultString(escape(myQuantity.getSystemElement().getValueAsString())));
}
b.append(ParameterUtil.escapeWithDefault(mySystem));
b.append('|');
if (!myQuantity.getUnitsElement().isEmpty()) {
b.append(defaultString(escape(myQuantity.getUnitsElement().getValueAsString())));
}
b.append(ParameterUtil.escapeWithDefault(myUnits));
return b.toString();
}
public String getValueAsString() {
if (myValue != null) {
return myValue.toPlainString();
}
return null;
}
@Override
void doSetValueAsQueryToken(String theQualifier, String theValue) {
clear();
@ -190,121 +238,145 @@ public class QuantityParam extends BaseParam implements IQueryParameterType {
List<String> parts = ParameterUtil.splitParameterString(theValue, '|', true);
if (parts.size() > 0 && StringUtils.isNotBlank(parts.get(0))) {
if (parts.get(0).startsWith("~")) {
myQuantity.setComparator((QuantityCompararatorEnum) null);
myApproximate = true;
myQuantity.setValue(new BigDecimal(parts.get(0).substring(1)));
} else if (parts.get(0).startsWith("<=")) {
myQuantity.setComparator(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS);
myQuantity.setValue(new BigDecimal(parts.get(0).substring(2)));
} else if (parts.get(0).startsWith("<")) {
myQuantity.setComparator(QuantityCompararatorEnum.LESSTHAN);
String valStr = parts.get(0).substring(1);
myQuantity.setValue(new BigDecimal(valStr));
} else if (parts.get(0).startsWith(">=")) {
myQuantity.setComparator(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS);
myQuantity.setValue(new BigDecimal(parts.get(0).substring(2)));
} else if (parts.get(0).startsWith(">")) {
myQuantity.setComparator(QuantityCompararatorEnum.GREATERTHAN);
myQuantity.setValue(new BigDecimal(parts.get(0).substring(1)));
} else {
myQuantity.setValue(new BigDecimal(parts.get(0)));
}
String value = super.extractPrefixAndReturnRest(parts.get(0));
setValue(value);
}
if (parts.size() > 1 && StringUtils.isNotBlank(parts.get(1))) {
myQuantity.setSystem(parts.get(1));
setSystem(parts.get(1));
}
if (parts.size() > 2 && StringUtils.isNotBlank(parts.get(2))) {
myQuantity.setUnits(parts.get(2));
setUnits(parts.get(2));
}
}
public QuantityCompararatorEnum getComparator() {
return myQuantity.getComparatorElement().getValueAsEnum();
/**
* Returns the system, or null if none was provided
* <p>
* Note that prior to HAPI FHIR 1.5, this method returned a {@link UriDt}
* </p>
*
* @since 1.5
*/
public String getSystem() {
return mySystem;
}
public UriDt getSystem() {
return myQuantity.getSystemElement();
/**
* @deprecated Use {{@link #getSystem()}} instead
*/
@Deprecated
@CoverageIgnore
public UriDt getSystemAsUriDt() {
return new UriDt(mySystem);
}
public String getUnits() {
return myQuantity.getUnitsElement().getValue();
return myUnits;
}
public DecimalDt getValue() {
return myQuantity.getValueElement();
/**
* Returns the quantity/value, or null if none was provided
* <p>
* Note that prior to HAPI FHIR 1.5, this method returned a {@link DecimalDt}
* </p>
*
* @since 1.5
*/
public BigDecimal getValue() {
return myValue;
}
/**
* @deprecated Use {@link #getValue()} instead
*/
@Deprecated
public DecimalDt getValueAsDecimalDt() {
return new DecimalDt(myValue);
}
/**
* @deprecated Use {@link #getPrefix()} with the {@link ParamPrefixEnum#APPROXIMATE} constant
*/
@Deprecated
public boolean isApproximate() {
return myApproximate;
return getPrefix() == ParamPrefixEnum.APPROXIMATE;
}
/**
* @deprecated Use {@link #setPrefix(ParamPrefixEnum)} with the {@link ParamPrefixEnum#APPROXIMATE} constant
*/
@Deprecated
public void setApproximate(boolean theApproximate) {
myApproximate = theApproximate;
if (theApproximate) {
myQuantity.setComparator((QuantityCompararatorEnum) null);
}
}
public QuantityParam setComparator(QuantityCompararatorEnum theComparator) {
myQuantity.setComparator(theComparator);
return this;
}
public QuantityParam setComparator(String theComparator) {
if ("~".equals(theComparator)) {
myApproximate = true;
myQuantity.setComparator(((QuantityCompararatorEnum) null));
setPrefix(ParamPrefixEnum.APPROXIMATE);
} else {
myApproximate = false;
myQuantity.setComparator(QuantityCompararatorEnum.VALUESET_BINDER.fromCodeString(theComparator));
setPrefix(null);
}
return this;
}
public QuantityParam setSystem(String theSystem) {
myQuantity.setSystem(theSystem);
mySystem = theSystem;
return this;
}
public QuantityParam setSystem(UriDt theSystem) {
myQuantity.setSystem(theSystem);
public QuantityParam setSystem(IPrimitiveType<String> theSystem) {
mySystem = null;
if (theSystem != null) {
mySystem = theSystem.getValue();
}
return this;
}
public QuantityParam setUnits(String theUnits) {
myQuantity.setUnits(theUnits);
myUnits = theUnits;
return this;
}
public QuantityParam setValue(BigDecimal theValue) {
myQuantity.setValue(theValue);
myValue = theValue;
return this;
}
public QuantityParam setValue(DecimalDt theValue) {
myQuantity.setValue(theValue);
public QuantityParam setValue(IPrimitiveType<BigDecimal> theValue) {
myValue = null;
if (theValue != null) {
myValue = theValue.getValue();
}
return this;
}
public QuantityParam setValue(String theValue) {
myValue = null;
if (theValue != null) {
myValue = new BigDecimal(theValue);
}
return this;
}
public QuantityParam setValue(double theValue) {
myQuantity.setValue(theValue);
// Use the valueOf here because the constructor gives crazy precision
// changes due to the floating point conversion
myValue = BigDecimal.valueOf(theValue);
return this;
}
public QuantityParam setValue(long theValue) {
myQuantity.setValue(theValue);
// Use the valueOf here because the constructor gives crazy precision
// changes due to the floating point conversion
myValue = BigDecimal.valueOf(theValue);
return this;
}
@Override
public String toString() {
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
b.append("cmp", myQuantity.getComparatorElement().getValueAsString());
b.append("value", myQuantity.getValueElement().getValueAsString());
b.append("system", myQuantity.getSystemElement().getValueAsString());
b.append("units", myQuantity.getUnitsElement().getValueAsString());
b.append("prefix", getPrefix());
b.append("value", myValue);
b.append("system", mySystem);
b.append("units", myUnits);
if (getMissing() != null) {
b.append("missing", getMissing());
}

View File

@ -22,6 +22,8 @@ package ca.uhn.fhir.rest.param;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.math.BigDecimal;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.hl7.fhir.instance.model.api.IBaseResource;
@ -29,24 +31,38 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.util.CoverageIgnore;
public class ReferenceParam extends IdDt implements IQueryParameterType {
public class ReferenceParam extends BaseParam implements IQueryParameterType {
private BaseParam myBase=new BaseParam.ComposableBaseParam();
private final IdDt myId = new IdDt();
private String myChain;
/**
* Constructor
*/
public ReferenceParam() {
super();
}
/**
* Constructor
*/
public ReferenceParam(String theValue) {
setValueAsQueryToken(null, theValue);
}
/**
* Constructor
*/
public ReferenceParam(String theChain, String theValue) {
setValueAsQueryToken(null, theValue);
setChain(theChain);
}
/**
* Constructor
*/
public ReferenceParam(String theResourceType, String theChain, String theValue) {
if (isNotBlank(theResourceType)) {
setValue(theResourceType + "/" + theValue);
@ -56,21 +72,120 @@ public class ReferenceParam extends IdDt implements IQueryParameterType {
setChain(theChain);
}
public void setValue(String theValue) {
myId.setValue(theValue);
}
public String getChain() {
return myChain;
}
@Override
public Boolean getMissing() {
return myBase.getMissing();
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 getQueryParameterQualifier() {
if (myBase.getMissing()!=null) {
return myBase.getQueryParameterQualifier();
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();
if (isNotBlank(getResourceType())) {
b.append(':');
@ -86,43 +201,21 @@ public class ReferenceParam extends IdDt implements IQueryParameterType {
return null;
}
public Class<? extends IBaseResource> getResourceType(FhirContext theCtx) {
if (isBlank(getResourceType())) {
return null;
}
return theCtx.getResourceDefinition(getResourceType()).getImplementingClass();
public String getResourceType() {
return myId.getResourceType();
}
@Override
public String getValueAsQueryToken() {
if (myBase.getMissing()!=null) {
return myBase.getValueAsQueryToken();
}
if (isBlank(getResourceType())) {
return getValue(); // e.g. urn:asdjd or 123 or cid:wieiuru or #1
String doGetValueAsQueryToken(FhirContext theContext) {
if (isBlank(myId.getResourceType())) {
return myId.getValue(); // e.g. urn:asdjd or 123 or cid:wieiuru or #1
} else {
return getIdPart();
return myId.getIdPart();
}
}
public void setChain(String theChain) {
myChain = theChain;
}
@Override
public void setMissing(Boolean theMissing) {
myBase.setMissing(theMissing);
}
@Override
public void setValueAsQueryToken(String theQualifier, String theValue) {
myBase.setValueAsQueryToken(theQualifier, theValue);
if (myBase.getMissing()!=null) {
myChain=null;
setValue(null);
return;
}
void doSetValueAsQueryToken(String theQualifier, String theValue) {
String q = theQualifier;
String resourceType = null;
if (isNotBlank(q)) {
@ -146,89 +239,27 @@ public class ReferenceParam extends IdDt implements IQueryParameterType {
}
}
/**
* 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() {
DateParam retVal = new DateParam();
retVal.setValueAsQueryToken(null, getValueAsQueryToken());
return retVal;
@CoverageIgnore
public String getIdPart() {
return myId.getIdPart();
}
/**
* 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() {
NumberParam retVal = new NumberParam();
retVal.setValueAsQueryToken(null, getValueAsQueryToken());
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() {
QuantityParam retVal = new QuantityParam();
retVal.setValueAsQueryToken(null, getValueAsQueryToken());
return retVal;
@CoverageIgnore
public Long getIdPartAsLong() {
return myId.getIdPartAsLong();
}
@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();
@CoverageIgnore
public BigDecimal getIdPartAsBigDecimal() {
return myId.getIdPartAsBigDecimal();
}
/**
* 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() {
StringParam retVal = new StringParam();
retVal.setValueAsQueryToken(null, getValueAsQueryToken());
return retVal;
@CoverageIgnore
public String getBaseUrl() {
return myId.getBaseUrl();
}
/**
* 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() {
TokenParam retVal = new TokenParam();
retVal.setValueAsQueryToken(null, getValueAsQueryToken());
return retVal;
public boolean hasResourceType() {
return myId.hasResourceType();
}
}

View File

@ -25,6 +25,7 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.rest.server.Constants;
@ -59,7 +60,7 @@ public class StringParam extends BaseParam implements IQueryParameterType {
}
@Override
String doGetValueAsQueryToken() {
String doGetValueAsQueryToken(FhirContext theContext) {
return ParameterUtil.escape(myValue);
}

View File

@ -26,6 +26,7 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.base.composite.BaseIdentifierDt;
@ -94,7 +95,7 @@ public class TokenParam extends BaseParam implements IQueryParameterType {
* {@inheritDoc}
*/
@Override
String doGetValueAsQueryToken() {
String doGetValueAsQueryToken(FhirContext theContext) {
if (getSystem() != null) {
return ParameterUtil.escape(StringUtils.defaultString(getSystem())) + '|' + ParameterUtil.escape(getValue());
} else {

View File

@ -25,15 +25,21 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.UriDt;
public class UriParam extends BaseParam implements IQueryParameterType {
private UriParamQualifierEnum myQualifier;
private String myValue;
/**
* Constructor
*/
public UriParam() {
super();
}
public UriParam(String theValue) {
@ -42,19 +48,27 @@ public class UriParam extends BaseParam implements IQueryParameterType {
@Override
String doGetQueryParameterQualifier() {
return null;
return myQualifier != null ? myQualifier.getValue() : null;
}
@Override
String doGetValueAsQueryToken() {
String doGetValueAsQueryToken(FhirContext theContext) {
return ParameterUtil.escape(myValue);
}
@Override
void doSetValueAsQueryToken(String theQualifier, String theValue) {
myQualifier = UriParamQualifierEnum.forValue(theQualifier);
myValue = ParameterUtil.unescape(theValue);
}
/**
* Gets the qualifier for this param (may be <code>null</code> and generally will be)
*/
public UriParamQualifierEnum getQualifier() {
return myQualifier;
}
public String getValue() {
return myValue;
}
@ -75,8 +89,24 @@ public class UriParam extends BaseParam implements IQueryParameterType {
return StringUtils.isEmpty(myValue);
}
public void setValue(String theValue) {
/**
* Sets the qualifier for this param (may be <code>null</code> and generally will be)
*
* @return Returns a reference to <code>this</code> for easy method chanining
*/
public UriParam setQualifier(UriParamQualifierEnum theQualifier) {
myQualifier = theQualifier;
return this;
}
/**
* Sets the value for this param
*
* @return Returns a reference to <code>this</code> for easy method chanining
*/
public UriParam setValue(String theValue) {
myValue = theValue;
return this;
}
@Override

View File

@ -0,0 +1,64 @@
package ca.uhn.fhir.rest.param;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Qualifiers for {@link UriParam}
*/
public enum UriParamQualifierEnum {
/**
* The search parameter is a concept with the form <code>[system]|[code]</code>,
* and the search parameter tests whether the coding in a resource subsumes the
* specified search code. For example, the search concept has an is-a relationship
* with the coding in the resource, and this includes the coding itself.
* <p>
* Value <code>:above</code>
* </p>
*/
ABOVE(":above"),
/**
* The search parameter is a concept with the form <code>[system]|[code]</code>,
* and the search parameter tests whether the coding in a resource subsumes the
* specified search code. For example, the search concept has an is-a relationship
* with the coding in the resource, and this includes the coding itself.
* <p>
* Value <code>:below</code>
* </p>
*/
BELOW(":below");
private static final Map<String, UriParamQualifierEnum> KEY_TO_VALUE;
static {
HashMap<String, UriParamQualifierEnum> key2value = new HashMap<String, UriParamQualifierEnum>();
for (UriParamQualifierEnum next : values()) {
key2value.put(next.getValue(), next);
}
KEY_TO_VALUE = Collections.unmodifiableMap(key2value);
}
private final String myValue;
private UriParamQualifierEnum(String theValue) {
myValue = theValue;
}
/**
* Returns the qualifier value, e.g. <code>:below</code>
*/
public String getValue() {
return myValue;
}
/**
* Returns the {@link UriParamQualifierEnum} matching the given qualifier value, such as <code>:below</code>,
* or <code>null</code>
*/
public static UriParamQualifierEnum forValue(String theValue) {
return KEY_TO_VALUE.get(theValue);
}
}

View File

@ -25,15 +25,18 @@ import javax.servlet.http.HttpServletRequest;
/**
* Works like the normal {@link ca.uhn.fhir.rest.server.IncomingRequestAddressStrategy} unless there's an x-forwarded-host present, in which case that's used in place of the server's address.
* <p>
* If the Apache Http Server <code>mod_proxy</code> isn't configured to supply <code>x-forwarded-proto</code>, the factory method that you use to create the address strategy will determine the default. Note that
* <code>mod_proxy</code> doesn't set this by default, but it can be configured via <code>RequestHeader set X-Forwarded-Proto http</code> (or https)
* </p>
* <p>
* If you want to set the protocol based on something other than the constructor argument, you should be able to do so by overriding <code>protocol</code>.
* </p>
* <p>
* Note that while this strategy was designed to work with Apache Http Server, and has been tested against it, it should work with any proxy server that sets <code>x-forwarded-host</code>
* </p>
*
* If the Apache Http Server <i>mod_proxy</i> isn't configured to supply <i>x-forwarded-proto</i>, the factory method that you use to create the address strategy will determine the default. Note that
* <i>mod_proxy</i> doesn't set this by default, but it can be configured via <i>RequestHeader set X-Forwarded-Proto http</i> (or https)
*
* If you want to set the protocol based on something other than the constructor argument, you should be able to do so by overriding <i>protocol</i>.
*
* Note that while this strategy was designed to work with Apache Http Server, and has been tested against it, it should work with any proxy server that sets <i>x-forwarded-host</i>
*
* Created by Bill de Beaubien on 3/30/2015.
* @author Created by Bill de Beaubien on 3/30/2015.
*/
public class ApacheProxyAddressStrategy extends IncomingRequestAddressStrategy {
private boolean myUseHttps = false;
@ -42,14 +45,6 @@ public class ApacheProxyAddressStrategy extends IncomingRequestAddressStrategy {
myUseHttps = theUseHttps;
}
public static ApacheProxyAddressStrategy forHttp() {
return new ApacheProxyAddressStrategy(false);
}
public static ApacheProxyAddressStrategy forHttps() {
return new ApacheProxyAddressStrategy(true);
}
@Override
public String determineServerBase(ServletContext theServletContext, HttpServletRequest theRequest) {
String forwardedHost = getForwardedHost(theRequest);
@ -59,17 +54,6 @@ public class ApacheProxyAddressStrategy extends IncomingRequestAddressStrategy {
return super.determineServerBase(theServletContext, theRequest);
}
private String getForwardedHost(HttpServletRequest theRequest) {
String forwardedHost = theRequest.getHeader("x-forwarded-host");
if (forwardedHost != null) {
int commaPos = forwardedHost.indexOf(',');
if (commaPos >= 0) {
forwardedHost = forwardedHost.substring(0, commaPos - 1);
}
}
return forwardedHost;
}
public String forwardedServerBase(ServletContext theServletContext, HttpServletRequest theRequest, String theForwardedHost) {
String serverBase = super.determineServerBase(theServletContext, theRequest);
String host = theRequest.getHeader("host");
@ -81,6 +65,17 @@ public class ApacheProxyAddressStrategy extends IncomingRequestAddressStrategy {
return serverBase;
}
private String getForwardedHost(HttpServletRequest theRequest) {
String forwardedHost = theRequest.getHeader("x-forwarded-host");
if (forwardedHost != null) {
int commaPos = forwardedHost.indexOf(',');
if (commaPos >= 0) {
forwardedHost = forwardedHost.substring(0, commaPos - 1);
}
}
return forwardedHost;
}
protected String protocol(HttpServletRequest theRequest) {
String protocol = theRequest.getHeader("x-forwarded-proto");
if (protocol != null) {
@ -88,4 +83,18 @@ public class ApacheProxyAddressStrategy extends IncomingRequestAddressStrategy {
}
return myUseHttps ? "https" : "http";
}
/**
* Static factory for instance using <code>http://</code>
*/
public static ApacheProxyAddressStrategy forHttp() {
return new ApacheProxyAddressStrategy(false);
}
/**
* Static factory for instance using <code>https://</code>
*/
public static ApacheProxyAddressStrategy forHttps() {
return new ApacheProxyAddressStrategy(true);
}
}

View File

@ -62,4 +62,7 @@ ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.invalidVersion=Version "{0}" is not
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.multipleParamsWithSameNameOneIsMissingTrue=This server does not know how to handle multiple "{0}" parameters where one has a value of :missing=true
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.unableToDeleteNotFound=Unable to find resource matching URL "{0}". Deletion failed.
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.successfulCreate=Successfully created resource "{0}" in {1}ms
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.successfulUpdate=Successfully updated resource "{0}" in {1}ms
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.successfulUpdate=Successfully updated resource "{0}" in {1}ms
ca.uhn.fhir.jpa.dao.SearchBuilder.invalidQuantityPrefix=Unable to handle quantity prefix "{0}" for value: {1}
ca.uhn.fhir.jpa.dao.SearchBuilder.invalidNumberPrefix=Unable to handle number prefix "{0}" for value: {1}

View File

@ -55,6 +55,7 @@ import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamUriDao;
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
import ca.uhn.fhir.jpa.entity.BaseHasResource;
import ca.uhn.fhir.jpa.entity.BaseTag;
@ -106,6 +107,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
protected ISearchDao mySearchDao;
@Autowired()
protected ISearchResultDao mySearchResultDao;
@Autowired()
protected IResourceIndexedSearchParamUriDao myResourceIndexedSearchParamUriDao;
private String mySecondaryPrimaryKeyParamName;
@ -912,7 +915,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName(), getContext());
notifyInterceptors(RestOperationTypeEnum.SEARCH_TYPE, requestDetails);
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this);
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this, myResourceIndexedSearchParamUriDao);
builder.setType(getResourceType(), getResourceName());
return builder.search(theParams);
}
@ -938,7 +941,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
@Override
public Set<Long> searchForIdsWithAndOr(SearchParameterMap theParams, Collection<Long> theInitialPids, DateRangeParam theLastUpdated) {
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this);
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this, myResourceIndexedSearchParamUriDao);
builder.setType(getResourceType(), getResourceName());
return builder.searchForIdsWithAndOr(theParams, theInitialPids, theLastUpdated);
}

View File

@ -60,7 +60,7 @@ public class FhirResourceDaoPatientDstu2 extends FhirResourceDaoDstu2<Patient>im
paramMap.add("_id", new StringParam(theId.getIdPart()));
}
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this);
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this, myResourceIndexedSearchParamUriDao);
builder.setType(getResourceType(), getResourceName());
return builder.search(paramMap);
}

View File

@ -26,6 +26,7 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.math.BigDecimal;
import java.math.MathContext;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -54,6 +55,7 @@ import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
@ -70,6 +72,7 @@ import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.RuntimeChildResourceDefinition;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamUriDao;
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
import ca.uhn.fhir.jpa.entity.BaseHasResource;
import ca.uhn.fhir.jpa.entity.BaseResourceIndexedSearchParam;
@ -94,7 +97,6 @@ import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.base.composite.BaseIdentifierDt;
import ca.uhn.fhir.model.base.composite.BaseQuantityDt;
import ca.uhn.fhir.model.dstu.resource.BaseResource;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
@ -105,11 +107,13 @@ import ca.uhn.fhir.rest.param.CompositeParam;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.NumberParam;
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
import ca.uhn.fhir.rest.param.QuantityParam;
import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.param.UriParam;
import ca.uhn.fhir.rest.param.UriParamQualifierEnum;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.SimpleBundleProvider;
@ -128,14 +132,16 @@ public class SearchBuilder {
private Class<? extends IBaseResource> myResourceType;
private ISearchDao mySearchDao;
private ISearchResultDao mySearchResultDao;
private IResourceIndexedSearchParamUriDao myResourceIndexedSearchParamUriDao;
public SearchBuilder(FhirContext theFhirContext, EntityManager theEntityManager, PlatformTransactionManager thePlatformTransactionManager, ISearchDao theSearchDao, ISearchResultDao theSearchResultDao, BaseHapiFhirDao theDao) {
public SearchBuilder(FhirContext theFhirContext, EntityManager theEntityManager, PlatformTransactionManager thePlatformTransactionManager, ISearchDao theSearchDao, ISearchResultDao theSearchResultDao, BaseHapiFhirDao theDao, IResourceIndexedSearchParamUriDao theResourceIndexedSearchParamUriDao) {
myContext = theFhirContext;
myEntityManager = theEntityManager;
myPlatformTransactionManager = thePlatformTransactionManager;
mySearchDao = theSearchDao;
mySearchResultDao = theSearchResultDao;
myCallingDao = theDao;
myResourceIndexedSearchParamUriDao = theResourceIndexedSearchParamUriDao;
}
private Set<Long> addPredicateComposite(RuntimeSearchParam theParamDef, Set<Long> thePids, List<? extends IQueryParameterType> theNextAnd) {
@ -350,30 +356,14 @@ public class SearchBuilder {
return thePids;
}
Path<Object> fromObj = from.get("myValue");
if (param.getComparator() == null) {
double mul = value.doubleValue() * 1.01;
double low = value.doubleValue() - mul;
double high = value.doubleValue() + mul;
Predicate lowPred = builder.ge(fromObj.as(Long.class), low);
Predicate highPred = builder.le(fromObj.as(Long.class), high);
codePredicates.add(builder.and(lowPred, highPred));
} else {
switch (param.getComparator()) {
case GREATERTHAN:
codePredicates.add(builder.greaterThan(fromObj.as(BigDecimal.class), value));
break;
case GREATERTHAN_OR_EQUALS:
codePredicates.add(builder.ge(fromObj.as(BigDecimal.class), value));
break;
case LESSTHAN:
codePredicates.add(builder.lessThan(fromObj.as(BigDecimal.class), value));
break;
case LESSTHAN_OR_EQUALS:
codePredicates.add(builder.le(fromObj.as(BigDecimal.class), value));
break;
}
}
final Expression<BigDecimal> fromObj = from.get("myValue");
ParamPrefixEnum prefix = ObjectUtils.defaultIfNull(param.getPrefix(), ParamPrefixEnum.EQUAL);
String invalidMessageName = "invalidNumberPrefix";
String valueAsString = param.getValue().toPlainString();
Predicate num = createPredicateNumeric(builder, params, prefix, value, fromObj, invalidMessageName, valueAsString);
codePredicates.add(num);
} else {
throw new IllegalArgumentException("Invalid token type: " + params.getClass());
}
@ -481,23 +471,24 @@ public class SearchBuilder {
String systemValue;
String unitsValue;
QuantityCompararatorEnum cmpValue;
ParamPrefixEnum cmpValue;
BigDecimal valueValue;
boolean approx = false;
String valueString;
if (params instanceof BaseQuantityDt) {
BaseQuantityDt param = (BaseQuantityDt) params;
systemValue = param.getSystemElement().getValueAsString();
unitsValue = param.getUnitsElement().getValueAsString();
cmpValue = QuantityCompararatorEnum.VALUESET_BINDER.fromCodeString(param.getComparatorElement().getValueAsString());
cmpValue = ParamPrefixEnum.forDstu1Value(param.getComparatorElement().getValueAsString());
valueValue = param.getValueElement().getValue();
valueString = param.getValueElement().getValueAsString();
} else if (params instanceof QuantityParam) {
QuantityParam param = (QuantityParam) params;
systemValue = param.getSystem().getValueAsString();
systemValue = param.getSystem();
unitsValue = param.getUnits();
cmpValue = param.getComparator();
valueValue = param.getValue().getValue();
approx = param.isApproximate();
cmpValue = param.getPrefix();
valueValue = param.getValue();
valueString = param.getValueAsString();
} else {
throw new IllegalArgumentException("Invalid quantity type: " + params.getClass());
}
@ -512,36 +503,11 @@ public class SearchBuilder {
code = builder.equal(from.get("myUnits"), unitsValue);
}
Predicate num;
if (cmpValue == null) {
BigDecimal mul = approx ? new BigDecimal(0.1) : new BigDecimal(0.01);
BigDecimal low = valueValue.subtract(valueValue.multiply(mul));
BigDecimal high = valueValue.add(valueValue.multiply(mul));
Predicate lowPred = builder.gt(from.get("myValue").as(BigDecimal.class), low);
Predicate highPred = builder.lt(from.get("myValue").as(BigDecimal.class), high);
num = builder.and(lowPred, highPred);
} else {
switch (cmpValue) {
case GREATERTHAN:
Expression<Number> path = from.get("myValue");
num = builder.gt(path, valueValue);
break;
case GREATERTHAN_OR_EQUALS:
path = from.get("myValue");
num = builder.ge(path, valueValue);
break;
case LESSTHAN:
path = from.get("myValue");
num = builder.lt(path, valueValue);
break;
case LESSTHAN_OR_EQUALS:
path = from.get("myValue");
num = builder.le(path, valueValue);
break;
default:
throw new IllegalStateException(cmpValue.getCode());
}
}
cmpValue = ObjectUtils.defaultIfNull(cmpValue, ParamPrefixEnum.EQUAL);
final Expression<BigDecimal> path = from.get("myValue");
String invalidMessageName = "invalidQuantityPrefix";
Predicate num = createPredicateNumeric(builder, params, cmpValue, valueValue, path, invalidMessageName, valueString);
if (system == null && code == null) {
codePredicates.add(num);
@ -602,7 +568,7 @@ public class SearchBuilder {
ReferenceParam ref = (ReferenceParam) params;
if (isBlank(ref.getChain())) {
String resourceId = ref.getValueAsQueryToken();
String resourceId = ref.getValueAsQueryToken(myContext);
if (resourceId.contains("/")) {
IIdType dt = new IdDt(resourceId);
resourceId = dt.getIdPart();
@ -790,7 +756,7 @@ public class SearchBuilder {
if (isNotBlank(nextParam.getValue())) {
haveTags = true;
} else if (isNotBlank(nextParam.getSystem())) {
throw new InvalidRequestException("Invalid " + theParamName + " parameter (must supply a value/code and not just a system): " + nextParam.getValueAsQueryToken());
throw new InvalidRequestException("Invalid " + theParamName + " parameter (must supply a value/code and not just a system): " + nextParam.getValueAsQueryToken(myContext));
}
} else {
UriParam nextParam = (UriParam) nextParamUncasted;
@ -942,13 +908,55 @@ public class SearchBuilder {
}
Path<Object> fromObj = from.get("myUri");
codePredicates.add(builder.equal(fromObj.as(String.class), value));
Predicate predicate;
if (param.getQualifier() == UriParamQualifierEnum.ABOVE) {
/*
* :above is an inefficient query- It means that the user is supplying a more specific URL
* (say http://example.com/foo/bar/baz) and that we should match on any URLs that are
* less specific but otherwise the same. For example http://example.com and http://example.com/foo
* would both match.
*
* We do this by querying the DB for all candidate URIs and then manually checking
* each one. This isn't very efficient, but this is also probably not a very common
* type of query to do.
*
* If we ever need to make this more efficient, lucene could certainly be used
* as an optimization.
*/
ourLog.info("Searching for candidate URI:above parameters for Resource[{}] param[{}]", myResourceName, theParamName);
Collection<String> candidates = myResourceIndexedSearchParamUriDao.findAllByResourceTypeAndParamName(myResourceName, theParamName);
List<String> toFind = new ArrayList<String>();
for (String next : candidates) {
if (value.length() >= next.length()) {
if (value.substring(0, next.length()).equals(next)) {
toFind.add(next);
}
}
}
if (toFind.isEmpty()) {
continue;
}
predicate = fromObj.as(String.class).in(toFind);
} else if (param.getQualifier() == UriParamQualifierEnum.BELOW) {
predicate = builder.like(fromObj.as(String.class), createLeftMatchLikeExpression(value));
} else {
predicate = builder.equal(fromObj.as(String.class), value);
}
codePredicates.add(predicate);
} else {
throw new IllegalArgumentException("Invalid URI type: " + params.getClass());
}
}
if (codePredicates.isEmpty()) {
return new HashSet<Long>();
}
Predicate masterCodePredicate = builder.or(toArray(codePredicates));
Predicate type = builder.equal(from.get("myResourceType"), myResourceName);
@ -1026,10 +1034,6 @@ public class SearchBuilder {
return p;
}
// private Set<Long> addPredicateComposite(String theParamName, Set<Long> thePids, List<? extends
// IQueryParameterType> theList) {
// }
private Predicate createPredicateDateFromRange(CriteriaBuilder theBuilder, From<ResourceIndexedSearchParamDate, ResourceIndexedSearchParamDate> theFrom, DateRangeParam theRange) {
Date lowerBound = theRange.getLowerBoundAsInstant();
Date upperBound = theRange.getUpperBoundAsInstant();
@ -1038,27 +1042,22 @@ public class SearchBuilder {
if (lowerBound != null) {
Predicate gt = theBuilder.greaterThanOrEqualTo(theFrom.<Date> get("myValueLow"), lowerBound);
Predicate lt = theBuilder.greaterThanOrEqualTo(theFrom.<Date> get("myValueHigh"), lowerBound);
lb = theBuilder.or(gt, lt);
// Predicate gin = builder.isNull(from.get("myValueLow"));
// Predicate lbo = builder.or(gt, gin);
// Predicate lin = builder.isNull(from.get("myValueHigh"));
// Predicate hbo = builder.or(lt, lin);
// lb = builder.and(lbo, hbo);
if (theRange.getLowerBound().getPrefix() == ParamPrefixEnum.STARTS_AFTER) {
lb = gt;
} else {
lb = theBuilder.or(gt, lt);
}
}
Predicate ub = null;
if (upperBound != null) {
Predicate gt = theBuilder.lessThanOrEqualTo(theFrom.<Date> get("myValueLow"), upperBound);
Predicate lt = theBuilder.lessThanOrEqualTo(theFrom.<Date> get("myValueHigh"), upperBound);
ub = theBuilder.or(gt, lt);
// Predicate gin = builder.isNull(from.get("myValueLow"));
// Predicate lbo = builder.or(gt, gin);
// Predicate lin = builder.isNull(from.get("myValueHigh"));
// Predicate ubo = builder.or(lt, lin);
// ub = builder.and(ubo, lbo);
if (theRange.getUpperBound().getPrefix() == ParamPrefixEnum.ENDS_BEFORE) {
ub = lt;
} else {
ub = theBuilder.or(gt, lt);
}
}
if (lb != null && ub != null) {
@ -1070,6 +1069,52 @@ public class SearchBuilder {
}
}
private Predicate createPredicateNumeric(CriteriaBuilder builder, IQueryParameterType params, ParamPrefixEnum cmpValue, BigDecimal valueValue, final Expression<BigDecimal> path, String invalidMessageName, String theValueString) {
Predicate num;
switch (cmpValue) {
case GREATERTHAN:
num = builder.gt(path, valueValue);
break;
case GREATERTHAN_OR_EQUALS:
num = builder.ge(path, valueValue);
break;
case LESSTHAN:
num = builder.lt(path, valueValue);
break;
case LESSTHAN_OR_EQUALS:
num = builder.le(path, valueValue);
break;
case APPROXIMATE:
case EQUAL:
case NOT_EQUAL:
BigDecimal mul = calculateFuzzAmount(cmpValue, valueValue);
BigDecimal low = valueValue.subtract(mul, MathContext.DECIMAL64);
BigDecimal high = valueValue.add(mul, MathContext.DECIMAL64);
Predicate lowPred;
Predicate highPred;
if (cmpValue != ParamPrefixEnum.NOT_EQUAL) {
lowPred = builder.ge(path.as(BigDecimal.class), low);
highPred = builder.le(path.as(BigDecimal.class), high);
ourLog.info("Searching for {} <= val <= {}", low, high);
num = builder.and(lowPred, highPred);
} else {
// Prefix was "ne", so reverse it!
lowPred = builder.lt(path.as(BigDecimal.class), low);
highPred = builder.gt(path.as(BigDecimal.class), high);
num = builder.or(lowPred, highPred);
}
break;
default:
String msg = myContext.getLocalizer().getMessage(SearchBuilder.class, invalidMessageName, cmpValue.getValue(), params.getValueAsQueryToken(myContext));
throw new InvalidRequestException(msg);
}
return num;
}
// private Set<Long> addPredicateComposite(String theParamName, Set<Long> thePids, List<? extends
// IQueryParameterType> theList) {
// }
private Predicate createPredicateString(IQueryParameterType theParameter, String theParamName, CriteriaBuilder theBuilder, From<ResourceIndexedSearchParamString, ResourceIndexedSearchParamString> theFrom) {
String rawSearchTerm;
if (theParameter instanceof TokenParam) {
@ -1093,7 +1138,7 @@ public class SearchBuilder {
}
String likeExpression = BaseHapiFhirDao.normalizeString(rawSearchTerm);
likeExpression = likeExpression.replace("%", "[%]") + "%";
likeExpression = createLeftMatchLikeExpression(likeExpression);
Predicate singleCode = theBuilder.like(theFrom.get("myValueNormalized").as(String.class), likeExpression);
if (theParameter instanceof StringParam && ((StringParam) theParameter).isExact()) {
@ -1103,6 +1148,10 @@ public class SearchBuilder {
return singleCode;
}
private static String createLeftMatchLikeExpression(String likeExpression) {
return likeExpression.replace("%", "[%]") + "%";
}
private Predicate createPredicateToken(IQueryParameterType theParameter, String theParamName, CriteriaBuilder theBuilder, From<ResourceIndexedSearchParamToken, ResourceIndexedSearchParamToken> theFrom) {
String code;
String system;
@ -1311,15 +1360,15 @@ public class SearchBuilder {
if (resource instanceof IResource) {
if (theRevIncludedPids.contains(next.getId())) {
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put((IResource)resource, BundleEntrySearchModeEnum.INCLUDE);
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put((IResource) resource, BundleEntrySearchModeEnum.INCLUDE);
} else {
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put((IResource)resource, BundleEntrySearchModeEnum.MATCH);
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put((IResource) resource, BundleEntrySearchModeEnum.MATCH);
}
} else {
if (theRevIncludedPids.contains(next.getId())) {
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put((IAnyResource)resource, BundleEntrySearchModeEnum.INCLUDE.getCode());
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put((IAnyResource) resource, BundleEntrySearchModeEnum.INCLUDE.getCode());
} else {
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put((IAnyResource)resource, BundleEntrySearchModeEnum.MATCH.getCode());
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put((IAnyResource) resource, BundleEntrySearchModeEnum.MATCH.getCode());
}
}
@ -1519,9 +1568,9 @@ public class SearchBuilder {
loadPids = new HashSet<Long>();
if (theParams.containsKey(Constants.PARAM_CONTENT) || theParams.containsKey(Constants.PARAM_TEXT)) {
List<Long> pids = mySearchDao.everything(myResourceName, theParams);
// if (pid != null) {
// loadPids.add(pid);
// }
// if (pid != null) {
// loadPids.add(pid);
// }
loadPids.addAll(pids);
} else {
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
@ -1694,7 +1743,7 @@ public class SearchBuilder {
continue;
} else {
for (IQueryParameterType next : nextValue) {
String value = next.getValueAsQueryToken();
String value = next.getValueAsQueryToken(myContext);
IIdType valueId = new IdDt(value);
try {
@ -1868,6 +1917,28 @@ public class SearchBuilder {
return qp;
}
/**
* Figures out the tolerance for a search. For example, if the user is searching for
* <code>4.00</code>, this method returns <code>0.005</code> because we shold actually
* match values which are <code>4 (+/-) 0.005</code> according to the FHIR specs.
*/
static BigDecimal calculateFuzzAmount(ParamPrefixEnum cmpValue, BigDecimal theValue) {
if (cmpValue == ParamPrefixEnum.APPROXIMATE) {
return theValue.multiply(new BigDecimal(0.1));
} else {
String plainString = theValue.toPlainString();
int dotIdx = plainString.indexOf('.');
if (dotIdx == -1) {
return new BigDecimal(0.5);
}
int precision = plainString.length() - (dotIdx);
double mul = Math.pow(10, -precision);
double val = mul * 5.0d;
return new BigDecimal(val);
}
}
static Predicate[] toArray(List<Predicate> thePredicates) {
return thePredicates.toArray(new Predicate[thePredicates.size()]);
}

View File

@ -0,0 +1,36 @@
package ca.uhn.fhir.jpa.dao.data;
import java.util.Collection;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2016 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%
*/
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamUri;
public interface IResourceIndexedSearchParamUriDao extends JpaRepository<ResourceIndexedSearchParamUri, Long> {
@Query("SELECT DISTINCT p.myUri FROM ResourceIndexedSearchParamUri p WHERE p.myResourceType = :resource_type AND p.myParamName = :param_name")
public Collection<String> findAllByResourceTypeAndParamName(@Param("resource_type") String theResourceType, @Param("param_name") String theParamName);
}

View File

@ -63,7 +63,7 @@ public class FhirResourceDaoPatientDstu3 extends FhirResourceDaoDstu3<Patient>im
paramMap.add("_id", new StringParam(theId.getIdPart()));
}
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this);
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this, myResourceIndexedSearchParamUriDao);
builder.setType(getResourceType(), getResourceName());
return builder.search(paramMap);
}

View File

@ -23,6 +23,7 @@ package ca.uhn.fhir.jpa.entity;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.Index;
import javax.persistence.Table;
import org.apache.commons.lang3.StringUtils;
@ -34,9 +35,9 @@ import org.hibernate.search.annotations.Field;
//@formatter:off
@Embeddable
@Entity
@Table(name = "HFJ_SPIDX_URI" /* , indexes = { @Index(name = "IDX_SP_TOKEN", columnList = "SP_SYSTEM,SP_VALUE") } */)
@org.hibernate.annotations.Table(appliesTo = "HFJ_SPIDX_URI", indexes = {
@org.hibernate.annotations.Index(name = "IDX_SP_URI", columnNames = { "RES_TYPE", "SP_NAME", "SP_URI" })
@Table(name = "HFJ_SPIDX_URI", indexes = {
@Index(name = "IDX_SP_URI", columnList = "RES_TYPE,SP_NAME,SP_URI"),
@Index(name = "IDX_SP_RESTYPE_NAME", columnList = "RES_TYPE,SP_NAME")
})
//@formatter:on
public class ResourceIndexedSearchParamUri extends BaseResourceIndexedSearchParam {

View File

@ -0,0 +1,98 @@
package ca.uhn.fhir.jpa.dao;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.*;
import java.math.BigDecimal;
import java.math.MathContext;
import org.junit.Test;
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
public class SearchBuilderTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchBuilderTest.class);
@Test
public void testAA() {
assertTrue(123.00004f <= 123.0001f);
}
@Test
public void testCalculateMultiplierEqualNoDecimal() {
BigDecimal in = new BigDecimal("200");
BigDecimal out = SearchBuilder.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertEquals("0.5", out.toPlainString());
}
@Test
public void testCalculateMultiplierEqualDecimalPrecision200_() {
BigDecimal in = new BigDecimal("200.");
BigDecimal out = SearchBuilder.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertEquals("0.5", out.toPlainString());
}
@Test
public void testCalculateMultiplierEqualDecimalPrecision123_010() {
BigDecimal in = new BigDecimal("123.010");
BigDecimal out = SearchBuilder.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertThat(out.toPlainString(), startsWith("0.0005"));
BigDecimal low = in.subtract(out, MathContext.DECIMAL64);
BigDecimal high = in.add(out, MathContext.DECIMAL64);
ourLog.info("{} <= {} <= {}", new Object[] {low.toPlainString(), in.toPlainString(), high.toPlainString()});
}
@Test
public void testCalculateMultiplierEqualDecimalPrecision200_0() {
BigDecimal in = new BigDecimal("200.0");
BigDecimal out = SearchBuilder.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertThat(out.toPlainString(), startsWith("0.05000000"));
}
@Test
public void testCalculateMultiplierEqualDecimalPrecision200_3() {
BigDecimal in = new BigDecimal("200.3");
BigDecimal out = SearchBuilder.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertThat(out.toPlainString(), startsWith("0.05000000"));
}
@Test
public void testCalculateMultiplierEqualDecimalPrecision200_300() {
BigDecimal in = new BigDecimal("200.300");
BigDecimal out = SearchBuilder.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertThat(out.toPlainString(), startsWith("0.0005000000"));
}
@Test
public void testCalculateMultiplierEqualDecimalPrecision200_30000000() {
BigDecimal in = new BigDecimal("200.30000000");
BigDecimal out = SearchBuilder.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertThat(out.toPlainString(), startsWith("0.000000005000000"));
}
@Test
public void testCalculateMultiplierEqualDecimalPrecision200_300000001() {
BigDecimal in = new BigDecimal("200.300000001");
BigDecimal out = SearchBuilder.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertThat(out.toPlainString(), startsWith("0.0000000005000000"));
}
@Test
public void testCalculateMultiplierApprox() {
BigDecimal in = new BigDecimal("200");
BigDecimal out = SearchBuilder.calculateFuzzAmount(ParamPrefixEnum.APPROXIMATE, in);
ourLog.info(out.toPlainString());
assertThat(out.toPlainString(), startsWith("20.000"));
}
}

View File

@ -8,7 +8,6 @@ import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@ -47,7 +46,6 @@ import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.dstu.resource.BaseResource;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
import ca.uhn.fhir.model.dstu2.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu2.composite.PeriodDt;
@ -84,6 +82,7 @@ import ca.uhn.fhir.rest.param.CompositeParam;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.NumberParam;
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
import ca.uhn.fhir.rest.param.QuantityParam;
import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.StringAndListParam;
@ -101,7 +100,7 @@ import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
@SuppressWarnings("unchecked")
public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu2SearchNoFtTest.class);
@Test
public void testCodeSearch() {
Subscription subs = new Subscription();
@ -109,7 +108,7 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
subs.getChannel().setType(SubscriptionChannelTypeEnum.WEBSOCKET);
subs.setCriteria("Observation?");
IIdType id = mySubscriptionDao.create(subs).getId().toUnqualifiedVersionless();
SearchParameterMap map = new SearchParameterMap();
map.add(Subscription.SP_TYPE, new TokenParam(null, SubscriptionChannelTypeEnum.WEBSOCKET.getCode()));
map.add(Subscription.SP_STATUS, new TokenParam(null, SubscriptionStatusEnum.ACTIVE.getCode()));
@ -119,15 +118,15 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
@Test
public void testEverythingTimings() throws Exception {
String methodName = "testEverythingIncludesBackReferences";
Organization org = new Organization();
org.setName(methodName);
IIdType orgId = myOrganizationDao.create(org).getId().toUnqualifiedVersionless();
Medication med = new Medication();
med.getCode().setText(methodName);
IIdType medId = myMedicationDao.create(med).getId().toUnqualifiedVersionless();
Patient pat = new Patient();
pat.addAddress().addLine(methodName);
pat.getManagingOrganization().setReference(orgId);
@ -142,7 +141,7 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
mo.getPatient().setReference(patId);
mo.setMedication(new ResourceReferenceDt(medId));
IIdType moId = myMedicationOrderDao.create(mo).getId().toUnqualifiedVersionless();
HttpServletRequest request = mock(HttpServletRequest.class);
IBundleProvider resp = myPatientDao.patientTypeEverything(request, null, null, null, null, null);
assertThat(toUnqualifiedVersionlessIds(resp), containsInAnyOrder(orgId, medId, patId, moId, patId2));
@ -161,18 +160,18 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
order.addItem().addEvent().setDateTime(new DateTimeDt("2011-12-12T11:12:12Z"));
order.addItem().addEvent().setDateTime(new DateTimeDt("2011-12-12T11:12:12Z"));
order.addItem().addEvent().setDateTime(new DateTimeDt("2011-12-12T11:12:12Z"));
IIdType id = myDiagnosticOrderDao.create(order).getId().toUnqualifiedVersionless();
List<IIdType> actual = toUnqualifiedVersionlessIds(myDiagnosticOrderDao.search(DiagnosticOrder.SP_ITEM_DATE, new DateParam("2011-12-12T11:12:12Z")));
assertThat(actual, contains(id));
Class<ResourceIndexedSearchParamDate> type = ResourceIndexedSearchParamDate.class;
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
ourLog.info(toStringMultiline(results));
assertEquals(2, results.size());
}
@Test
public void testIndexNoDuplicatesNumber() {
Immunization res = new Immunization();
@ -182,18 +181,18 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
res.addVaccinationProtocol().setDoseSequence(2);
res.addVaccinationProtocol().setDoseSequence(2);
res.addVaccinationProtocol().setDoseSequence(2);
IIdType id = myImmunizationDao.create(res).getId().toUnqualifiedVersionless();
List<IIdType> actual = toUnqualifiedVersionlessIds(myImmunizationDao.search(Immunization.SP_DOSE_SEQUENCE, new NumberParam("1")));
assertThat(actual, contains(id));
Class<ResourceIndexedSearchParamNumber> type = ResourceIndexedSearchParamNumber.class;
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
ourLog.info(toStringMultiline(results));
assertEquals(2, results.size());
}
@Test
public void testIndexNoDuplicatesQuantity() {
Substance res = new Substance();
@ -201,42 +200,42 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
res.addInstance().getQuantity().setSystem("http://foo").setCode("UNIT").setValue(123);
res.addInstance().getQuantity().setSystem("http://foo2").setCode("UNIT2").setValue(1232);
res.addInstance().getQuantity().setSystem("http://foo2").setCode("UNIT2").setValue(1232);
IIdType id = mySubstanceDao.create(res).getId().toUnqualifiedVersionless();
Class<ResourceIndexedSearchParamQuantity> type = ResourceIndexedSearchParamQuantity.class;
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
ourLog.info(toStringMultiline(results));
assertEquals(2, results.size());
List<IIdType> actual = toUnqualifiedVersionlessIds(mySubstanceDao.search(Substance.SP_QUANTITY, new QuantityParam(null, 123, "http://foo", "UNIT")));
List<IIdType> actual = toUnqualifiedVersionlessIds(mySubstanceDao.search(Substance.SP_QUANTITY, new QuantityParam((ParamPrefixEnum) null, 123, "http://foo", "UNIT")));
assertThat(actual, contains(id));
}
@Test
public void testIndexNoDuplicatesReference() {
Practitioner pract =new Practitioner();
Practitioner pract = new Practitioner();
pract.setId("Practitioner/somepract");
pract.getName().addFamily("SOME PRACT");
myPractitionerDao.update(pract);
Practitioner pract2 =new Practitioner();
Practitioner pract2 = new Practitioner();
pract2.setId("Practitioner/somepract2");
pract2.getName().addFamily("SOME PRACT2");
myPractitionerDao.update(pract2);
DiagnosticOrder res = new DiagnosticOrder();
res.addEvent().setActor(new ResourceReferenceDt("Practitioner/somepract"));
res.addEvent().setActor(new ResourceReferenceDt("Practitioner/somepract"));
res.addEvent().setActor(new ResourceReferenceDt("Practitioner/somepract2"));
res.addEvent().setActor(new ResourceReferenceDt("Practitioner/somepract2"));
IIdType id = myDiagnosticOrderDao.create(res).getId().toUnqualifiedVersionless();
Class<ResourceLink> type = ResourceLink.class;
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
ourLog.info(toStringMultiline(results));
assertEquals(2, results.size());
List<IIdType> actual = toUnqualifiedVersionlessIds(myDiagnosticOrderDao.search(DiagnosticOrder.SP_ACTOR, new ReferenceParam("Practitioner/somepract")));
assertThat(actual, contains(id));
}
@ -250,14 +249,14 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
p.addAddress().addLine("456 Fake Street");
p.addAddress().addLine("456 Fake Street");
p.addAddress().addLine("456 Fake Street");
IIdType id = myPatientDao.create(p).getId().toUnqualifiedVersionless();
Class<ResourceIndexedSearchParamString> type = ResourceIndexedSearchParamString.class;
List<ResourceIndexedSearchParamString> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
ourLog.info(toStringMultiline(results));
assertEquals(2, results.size());
List<IIdType> actual = toUnqualifiedVersionlessIds(myPatientDao.search(Patient.SP_ADDRESS, new StringParam("123 Fake Street")));
assertThat(actual, contains(id));
}
@ -269,14 +268,14 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
res.addIdentifier().setSystem("http://foo1").setValue("123");
res.addIdentifier().setSystem("http://foo2").setValue("1234");
res.addIdentifier().setSystem("http://foo2").setValue("1234");
IIdType id = myPatientDao.create(res).getId().toUnqualifiedVersionless();
Class<ResourceIndexedSearchParamToken> type = ResourceIndexedSearchParamToken.class;
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
ourLog.info(toStringMultiline(results));
assertEquals(2, results.size());
List<IIdType> actual = toUnqualifiedVersionlessIds(myPatientDao.search(Patient.SP_IDENTIFIER, new TokenParam("http://foo1", "123")));
assertThat(actual, contains(id));
}
@ -288,14 +287,14 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
res.addElement().addTarget().addDependsOn().setElement("http://foo");
res.addElement().addTarget().addDependsOn().setElement("http://bar");
res.addElement().addTarget().addDependsOn().setElement("http://bar");
IIdType id = myConceptMapDao.create(res).getId().toUnqualifiedVersionless();
Class<ResourceIndexedSearchParamUri> type = ResourceIndexedSearchParamUri.class;
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
ourLog.info(toStringMultiline(results));
assertEquals(2, results.size());
List<IIdType> actual = toUnqualifiedVersionlessIds(myConceptMapDao.search(ConceptMap.SP_DEPENDSON, new UriParam("http://foo")));
assertThat(actual, contains(id));
}
@ -319,7 +318,7 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
List<IBaseResource> patients = toList(myPatientDao.search(params));
assertTrue(patients.size() >= 2);
}
@Test
public void testSearchByIdParam() {
IIdType id1;
@ -364,7 +363,7 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
SearchParameterMap params;
StringAndListParam param;
params = new SearchParameterMap();
param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam(id1.getIdPart())).addOr(new StringParam(id2.getIdPart())));
@ -378,21 +377,21 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
param.addAnd(new StringOrListParam().addOr(new StringParam(id1.getIdPart())));
params.add("_id", param);
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), empty());
params = new SearchParameterMap();
param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam(id2.getIdPart())));
param.addAnd(new StringOrListParam().addOr(new StringParam("9999999999999")));
params.add("_id", param);
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), empty());
params = new SearchParameterMap();
param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("9999999999999")));
param.addAnd(new StringOrListParam().addOr(new StringParam(id2.getIdPart())));
params.add("_id", param);
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), empty());
}
@Test
@ -424,7 +423,7 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1));
// With lastupdated
params = new SearchParameterMap();
params.add("_id", new StringOrListParam().addOr(new StringParam(id1.getIdPart())).addOr(new StringParam(id2.getIdPart())));
params.setLastUpdated(new DateRangeParam(new Date(betweenTime), null));
@ -515,7 +514,6 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
}
/**
* #222
*/
@ -545,7 +543,7 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
assertEquals(1, toList(myPatientDao.search(params)).size());
myPatientDao.delete(new IdDt("Patient/TEST"));
params = new HashMap<String, IQueryParameterType>();
params.put("_id", new StringDt("TEST"));
assertEquals(0, toList(myPatientDao.search(params)).size());
@ -559,7 +557,6 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
params.put(Patient.SP_NAME, new StringParam("TEST"));
assertEquals(0, toList(myPatientDao.search(params)).size());
}
@Test
@ -611,7 +608,7 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
assertEquals(0, patients.size());
}
}
@Test
public void testSearchLanguageParamAndOr() {
IIdType id1;
@ -622,9 +619,9 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
patient.addName().addFamily("testSearchLanguageParam").addGiven("Joe");
id1 = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
Date betweenTime = new Date();
IIdType id2;
{
Patient patient = new Patient();
@ -783,7 +780,7 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
}
int sleep = 100;
long start = System.currentTimeMillis();
Thread.sleep(sleep);
@ -800,42 +797,42 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
patient.addIdentifier().setSystem("urn:system").setValue("001");
id1b = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
ourLog.info("Res 1: {}", ResourceMetadataKeyEnum.PUBLISHED.get(myPatientDao.read(id0)).getValueAsString());
ourLog.info("Res 2: {}", ResourceMetadataKeyEnum.PUBLISHED.get(myPatientDao.read(id1a)).getValueAsString());
InstantDt id1bpublished = ResourceMetadataKeyEnum.PUBLISHED.get(myPatientDao.read(id1b));
ourLog.info("Res 3: {}", id1bpublished.getValueAsString());
Thread.sleep(sleep);
long end = System.currentTimeMillis();
SearchParameterMap map;
Date startDate = new Date(start);
Date endDate = new Date(end);
DateTimeDt startDateTime = new DateTimeDt(startDate, TemporalPrecisionEnum.MILLI);
DateTimeDt endDateTime = new DateTimeDt(endDate, TemporalPrecisionEnum.MILLI);
map = new SearchParameterMap();
map.setLastUpdated(new DateRangeParam(startDateTime, endDateTime));
ourLog.info("Searching: {}", map.getLastUpdated());
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), containsInAnyOrder(id1a, id1b));
map = new SearchParameterMap();
map.setLastUpdated(new DateRangeParam(new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, startDateTime), new DateParam(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS, endDateTime)));
ourLog.info("Searching: {}", map.getLastUpdated());
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), containsInAnyOrder(id1a, id1b));
map = new SearchParameterMap();
map.setLastUpdated(new DateRangeParam(new DateParam(QuantityCompararatorEnum.GREATERTHAN, startDateTime), new DateParam(QuantityCompararatorEnum.LESSTHAN, endDateTime)));
map.setLastUpdated(new DateRangeParam(new DateParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, startDateTime), new DateParam(ParamPrefixEnum.LESSTHAN_OR_EQUALS, endDateTime)));
ourLog.info("Searching: {}", map.getLastUpdated());
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), containsInAnyOrder(id1a, id1b));
map = new SearchParameterMap();
map.setLastUpdated(new DateRangeParam(new DateParam(QuantityCompararatorEnum.GREATERTHAN, startDateTime.getValue()), new DateParam(QuantityCompararatorEnum.LESSTHAN, id1bpublished.getValue())));
map.setLastUpdated(new DateRangeParam(new DateParam(ParamPrefixEnum.GREATERTHAN, startDateTime), new DateParam(ParamPrefixEnum.LESSTHAN, endDateTime)));
ourLog.info("Searching: {}", map.getLastUpdated());
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), containsInAnyOrder(id1a, id1b));
map = new SearchParameterMap();
map.setLastUpdated(new DateRangeParam(new DateParam(ParamPrefixEnum.GREATERTHAN, startDateTime.getValue()), new DateParam(ParamPrefixEnum.LESSTHAN, id1bpublished.getValue())));
ourLog.info("Searching: {}", map.getLastUpdated());
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), containsInAnyOrder(id1a));
}
@Test
public void testSearchNameParam() {
IIdType id1;
@ -897,8 +894,7 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
myLocationDao.create(loc);
}
}
@Test
public void testSearchNumberParam() {
Encounter e1 = new Encounter();
@ -920,13 +916,16 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
assertEquals(0, found.size());
}
{
IBundleProvider found = myEncounterDao.search(Encounter.SP_LENGTH, new NumberParam("2"));
IBundleProvider found = myEncounterDao.search(Encounter.SP_LENGTH, new NumberParam("4"));
assertEquals(1, found.size());
assertThat(toUnqualifiedVersionlessIds(found), containsInAnyOrder(id1.toUnqualifiedVersionless()));
}
{
IBundleProvider found = myEncounterDao.search(Encounter.SP_LENGTH, new NumberParam("2"));
assertEquals(0, found.size());
}
}
@Test
public void testSearchParamChangesType() {
String name = "testSearchParamChangesType";
@ -953,7 +952,7 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
assertThat(patients, not(contains(id)));
}
@Test
public void testSearchPractitionerPhoneAndEmailParam() {
String methodName = "testSearchPractitionerPhoneAndEmailParam";
@ -1126,7 +1125,7 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
ourLog.info("P1[{}] L1[{}] Obs1[{}] Obs2[{}]", new Object[] { patientId01, locId01, obsId01, obsId02 });
List<Observation> result;
result = toList(myObservationDao.search(Observation.SP_SUBJECT, new ReferenceParam("Patient", Patient.SP_NAME, "testSearchResourceLinkWithChainWithMultipleTypes01")));
assertEquals(1, result.size());
assertEquals(obsId01.getIdPart(), result.get(0).getId().getIdPart());
@ -1382,7 +1381,7 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
QuantityParam param;
Set<Long> found;
param = new QuantityParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), null, null);
param = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), null, null);
found = myObservationDao.searchForIds("value-quantity", param);
int initialSize = found.size();
@ -1393,19 +1392,19 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
myObservationDao.create(o);
param = new QuantityParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), null, null);
param = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), null, null);
found = myObservationDao.searchForIds("value-quantity", param);
assertEquals(1 + initialSize, found.size());
param = new QuantityParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), null, methodName + "units");
param = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), null, methodName + "units");
found = myObservationDao.searchForIds("value-quantity", param);
assertEquals(1, found.size());
param = new QuantityParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), "urn:bar:" + methodName, null);
param = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), "urn:bar:" + methodName, null);
found = myObservationDao.searchForIds("value-quantity", param);
assertEquals(1, found.size());
param = new QuantityParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), "urn:bar:" + methodName, methodName + "units");
param = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), "urn:bar:" + methodName, methodName + "units");
found = myObservationDao.searchForIds("value-quantity", param);
assertEquals(1, found.size());
@ -1415,8 +1414,8 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
public void testSearchWithEmptySort() {
SearchParameterMap criteriaUrl = new SearchParameterMap();
DateRangeParam range = new DateRangeParam();
range.setLowerBound(new DateParam(QuantityCompararatorEnum.GREATERTHAN, 1000000));
range.setUpperBound(new DateParam(QuantityCompararatorEnum.LESSTHAN, 2000000));
range.setLowerBound(new DateParam(ParamPrefixEnum.GREATERTHAN, 1000000));
range.setUpperBound(new DateParam(ParamPrefixEnum.LESSTHAN, 2000000));
criteriaUrl.setLastUpdated(range);
criteriaUrl.setSort(new SortSpec(Constants.PARAM_LASTUPDATED, SortOrderEnum.ASC));
IBundleProvider results = myObservationDao.search(criteriaUrl);
@ -1991,9 +1990,9 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
ResourceMetadataKeyEnum.TAG_LIST.put(org, tagList);
tag1id = myOrganizationDao.create(org).getId().toUnqualifiedVersionless();
}
Date betweenDate = new Date();
IIdType tag2id;
{
Organization org = new Organization();
@ -2064,7 +2063,7 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
}
}
@Test
public void testSearchWithToken() {
IIdType notMissing;
@ -2109,7 +2108,7 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
myValueSetDao.update(vs);
IBundleProvider result = myValueSetDao.search(ValueSet.SP_URL, new UriParam("http://hl7.org/fhir/ValueSet/basic-resource-type"));
assertThat(toUnqualifiedVersionlessIds(result), contains((IIdType)new IdDt("ValueSet/testSearchWithUriParam")));
assertThat(toUnqualifiedVersionlessIds(result), contains((IIdType) new IdDt("ValueSet/testSearchWithUriParam")));
}
private String toStringMultiline(List<?> theResults) {
@ -2121,5 +2120,4 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
return b.toString();
}
}

View File

@ -247,20 +247,51 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
assertEquals(1, found.size());
assertEquals(id3, found.getResources(0, 1).get(0).getIdElement());
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("gt100", "foo", "bar"));
assertEquals(1, found.size());
assertEquals(id3, found.getResources(0, 1).get(0).getIdElement());
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("<100", "foo", "bar"));
assertEquals(0, found.size());
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("lt100", "foo", "bar"));
assertEquals(0, found.size());
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.0001", "foo", "bar"));
assertEquals(1, found.size());
assertEquals(id3, found.getResources(0, 1).get(0).getIdElement());
assertEquals(0, found.size());
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("~120", "foo", "bar"));
assertEquals(1, found.size());
assertEquals(id3, found.getResources(0, 1).get(0).getIdElement());
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("ap120", "foo", "bar"));
assertEquals(1, found.size());
assertEquals(id3, found.getResources(0, 1).get(0).getIdElement());
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("eq123", "foo", "bar"));
assertEquals(1, found.size());
assertEquals(id3, found.getResources(0, 1).get(0).getIdElement());
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("eq120", "foo", "bar"));
assertEquals(0, found.size());
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("ne120", "foo", "bar"));
assertEquals(1, found.size());
assertEquals(id3, found.getResources(0, 1).get(0).getIdElement());
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("ne123", "foo", "bar"));
assertEquals(0, found.size());
}
}
@Test
@ -1696,7 +1727,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
assertEquals(1, found.size());
found = toList(myObservationDao.search("value-quantity", new QuantityDt(112)));
assertEquals(1, found.size());
assertEquals(0, found.size());
found = toList(myObservationDao.search("value-quantity", new QuantityDt(212)));
assertEquals(0, found.size());

View File

@ -75,6 +75,7 @@ import ca.uhn.fhir.rest.param.CompositeParam;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.NumberParam;
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
import ca.uhn.fhir.rest.param.QuantityParam;
import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.StringAndListParam;
@ -84,6 +85,7 @@ import ca.uhn.fhir.rest.param.TokenAndListParam;
import ca.uhn.fhir.rest.param.TokenOrListParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.param.UriParam;
import ca.uhn.fhir.rest.param.UriParamQualifierEnum;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
@ -200,7 +202,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
ourLog.info(toStringMultiline(results));
assertEquals(2, results.size());
List<IIdType> actual = toUnqualifiedVersionlessIds(mySubstanceDao.search(Substance.SP_QUANTITY, new QuantityParam(null, 123, "http://foo", "UNIT")));
List<IIdType> actual = toUnqualifiedVersionlessIds(mySubstanceDao.search(Substance.SP_QUANTITY, new QuantityParam((ParamPrefixEnum)null, 123, "http://foo", "UNIT")));
assertThat(actual, contains(id));
}
@ -908,7 +910,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
assertEquals(0, found.size());
}
{
IBundleProvider found = myEncounterDao.search(Encounter.SP_LENGTH, new NumberParam("2"));
IBundleProvider found = myEncounterDao.search(Encounter.SP_LENGTH, new NumberParam("4"));
assertEquals(1, found.size());
assertThat(toUnqualifiedVersionlessIds(found), containsInAnyOrder(id1.toUnqualifiedVersionless()));
}
@ -2056,17 +2058,85 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
}
}
@Test
public void testSearchWithUriParamAbove() throws Exception {
ValueSet vs1 = new ValueSet();
vs1.setUrl("http://hl7.org/foo/baz");
myValueSetDao.create(vs1).getId().toUnqualifiedVersionless();
ValueSet vs2 = new ValueSet();
vs2.setUrl("http://hl7.org/foo/bar");
IIdType id2 = myValueSetDao.create(vs2).getId().toUnqualifiedVersionless();
ValueSet vs3 = new ValueSet();
vs3.setUrl("http://hl7.org/foo/bar/baz");
IIdType id3 = myValueSetDao.create(vs3).getId().toUnqualifiedVersionless();
IBundleProvider result;
result = myValueSetDao.search(ValueSet.SP_URL, new UriParam("http://hl7.org/foo/bar/baz/boz").setQualifier(UriParamQualifierEnum.ABOVE));
assertThat(toUnqualifiedVersionlessIds(result), containsInAnyOrder(id2, id3));
result = myValueSetDao.search(ValueSet.SP_URL, new UriParam("http://hl7.org/foo/bar/baz").setQualifier(UriParamQualifierEnum.ABOVE));
assertThat(toUnqualifiedVersionlessIds(result), containsInAnyOrder(id2, id3));
result = myValueSetDao.search(ValueSet.SP_URL, new UriParam("http://hl7.org/foo/bar").setQualifier(UriParamQualifierEnum.ABOVE));
assertThat(toUnqualifiedVersionlessIds(result), containsInAnyOrder(id2));
result = myValueSetDao.search(ValueSet.SP_URL, new UriParam("http://hl7.org/fhir/ValueSet/basic-resource-type").setQualifier(UriParamQualifierEnum.ABOVE));
assertThat(toUnqualifiedVersionlessIds(result), empty());
result = myValueSetDao.search(ValueSet.SP_URL, new UriParam("http://hl7.org").setQualifier(UriParamQualifierEnum.ABOVE));
assertThat(toUnqualifiedVersionlessIds(result), empty());
}
@Test
public void testSearchWithUriParam() throws Exception {
Class<ValueSet> type = ValueSet.class;
String resourceName = "/valueset-dstu2.json";
ValueSet vs = loadResourceFromClasspath(type, resourceName);
myValueSetDao.update(vs);
IIdType id1 = myValueSetDao.update(vs).getId().toUnqualifiedVersionless();
IBundleProvider result = myValueSetDao.search(ValueSet.SP_URL, new UriParam("http://hl7.org/fhir/ValueSet/basic-resource-type"));
assertThat(toUnqualifiedVersionlessIds(result), contains((IIdType)new IdType("ValueSet/testSearchWithUriParam")));
ValueSet vs2 = new ValueSet();
vs2.setUrl("http://hl7.org/foo/bar");
IIdType id2 = myValueSetDao.create(vs2).getId().toUnqualifiedVersionless();
IBundleProvider result;
result = myValueSetDao.search(ValueSet.SP_URL, new UriParam("http://hl7.org/fhir/ValueSet/basic-resource-type"));
assertThat(toUnqualifiedVersionlessIds(result), contains(id1));
result = myValueSetDao.search(ValueSet.SP_URL, new UriParam("http://hl7.org/fhir/ValueSet/basic-resource-type").setQualifier(UriParamQualifierEnum.BELOW));
assertThat(toUnqualifiedVersionlessIds(result), contains(id1));
result = myValueSetDao.search(ValueSet.SP_URL, new UriParam("http://hl7.org/fhir/ValueSet/").setQualifier(UriParamQualifierEnum.BELOW));
assertThat(toUnqualifiedVersionlessIds(result), contains(id1));
}
@Test
public void testSearchWithUriParamBelow() throws Exception {
Class<ValueSet> type = ValueSet.class;
String resourceName = "/valueset-dstu2.json";
ValueSet vs = loadResourceFromClasspath(type, resourceName);
IIdType id1 = myValueSetDao.update(vs).getId().toUnqualifiedVersionless();
ValueSet vs2 = new ValueSet();
vs2.setUrl("http://hl7.org/foo/bar");
IIdType id2 = myValueSetDao.create(vs2).getId().toUnqualifiedVersionless();
IBundleProvider result;
result = myValueSetDao.search(ValueSet.SP_URL, new UriParam("http://").setQualifier(UriParamQualifierEnum.BELOW));
assertThat(toUnqualifiedVersionlessIds(result), containsInAnyOrder(id1, id2));
result = myValueSetDao.search(ValueSet.SP_URL, new UriParam("http://hl7.org").setQualifier(UriParamQualifierEnum.BELOW));
assertThat(toUnqualifiedVersionlessIds(result), containsInAnyOrder(id1, id2));
result = myValueSetDao.search(ValueSet.SP_URL, new UriParam("http://hl7.org/foo").setQualifier(UriParamQualifierEnum.BELOW));
assertThat(toUnqualifiedVersionlessIds(result), containsInAnyOrder(id2));
result = myValueSetDao.search(ValueSet.SP_URL, new UriParam("http://hl7.org/foo/baz").setQualifier(UriParamQualifierEnum.BELOW));
assertThat(toUnqualifiedVersionlessIds(result), containsInAnyOrder());
}
private String toStringMultiline(List<?> theResults) {
StringBuilder b = new StringBuilder();
for (Object next : theResults) {

View File

@ -233,6 +233,86 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
}
}
@Test
public void testChoiceParamDateRange() {
Observation o1 = new Observation();
o1.getCode().addCoding().setSystem("foo").setCode("testChoiceParamDateRange01");
o1.setEffective(new Period().setStartElement(new DateTimeType("2015-01-01T00:00:00Z")).setEndElement(new DateTimeType("2015-01-10T00:00:00Z")));
IIdType id1 = myObservationDao.create(o1).getId().toUnqualifiedVersionless();
Observation o2 = new Observation();
o2.getCode().addCoding().setSystem("foo").setCode("testChoiceParamDateRange02");
o2.setEffective(new Period().setStartElement(new DateTimeType("2015-01-05T00:00:00Z")).setEndElement(new DateTimeType("2015-01-15T00:00:00Z")));
IIdType id2 = myObservationDao.create(o2).getId().toUnqualifiedVersionless();
{
IBundleProvider found = myObservationDao.search(Observation.SP_DATE, new DateParam("ge2015-01-02T00:00:00Z"));
List<IIdType> list = toUnqualifiedVersionlessIds(found);
assertThat(list, containsInAnyOrder(id1, id2));
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_DATE, new DateParam("gt2015-01-02T00:00:00Z"));
List<IIdType> list = toUnqualifiedVersionlessIds(found);
assertThat(list, containsInAnyOrder(id1, id2));
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_DATE, new DateParam("gt2015-01-10T00:00:00Z"));
List<IIdType> list = toUnqualifiedVersionlessIds(found);
assertThat(list, containsInAnyOrder(id2));
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_DATE, new DateParam("sa2015-01-02T00:00:00Z"));
List<IIdType> list = toUnqualifiedVersionlessIds(found);
assertThat(list, containsInAnyOrder(id2));
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_DATE, new DateParam("eb2015-01-13T00:00:00Z"));
List<IIdType> list = toUnqualifiedVersionlessIds(found);
assertThat(list, containsInAnyOrder(id1));
}
}
@Test
public void testChoiceParamQuantityPrecision() {
Observation o3 = new Observation();
o3.getCode().addCoding().setSystem("foo").setCode("testChoiceParam03");
o3.setValue(new Quantity(null, 123.01, "foo", "bar", "bar"));
IIdType id3 = myObservationDao.create(o3).getId().toUnqualifiedVersionless();
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("123", "foo", "bar"));
List<IIdType> list = toUnqualifiedVersionlessIds(found);
assertThat(list, containsInAnyOrder(id3));
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.0", "foo", "bar"));
List<IIdType> list = toUnqualifiedVersionlessIds(found);
assertThat(list, containsInAnyOrder(id3));
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.01", "foo", "bar"));
List<IIdType> list = toUnqualifiedVersionlessIds(found);
assertThat(list, containsInAnyOrder(id3));
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.010", "foo", "bar"));
List<IIdType> list = toUnqualifiedVersionlessIds(found);
assertThat(list, containsInAnyOrder(id3));
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.02", "foo", "bar"));
List<IIdType> list = toUnqualifiedVersionlessIds(found);
assertThat(list, containsInAnyOrder());
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.001", "foo", "bar"));
List<IIdType> list = toUnqualifiedVersionlessIds(found);
assertThat(list, containsInAnyOrder());
}
}
@Test
public void testChoiceParamQuantity() {
Observation o3 = new Observation();
@ -245,20 +325,51 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
assertEquals(1, found.size());
assertEquals(id3, found.getResources(0, 1).get(0).getIdElement());
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("gt100", "foo", "bar"));
assertEquals(1, found.size());
assertEquals(id3, found.getResources(0, 1).get(0).getIdElement());
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("<100", "foo", "bar"));
assertEquals(0, found.size());
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("lt100", "foo", "bar"));
assertEquals(0, found.size());
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("123.0001", "foo", "bar"));
assertEquals(1, found.size());
assertEquals(id3, found.getResources(0, 1).get(0).getIdElement());
assertEquals(0, found.size());
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("~120", "foo", "bar"));
assertEquals(1, found.size());
assertEquals(id3, found.getResources(0, 1).get(0).getIdElement());
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("ap120", "foo", "bar"));
assertEquals(1, found.size());
assertEquals(id3, found.getResources(0, 1).get(0).getIdElement());
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("eq123", "foo", "bar"));
assertEquals(1, found.size());
assertEquals(id3, found.getResources(0, 1).get(0).getIdElement());
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("eq120", "foo", "bar"));
assertEquals(0, found.size());
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("ne120", "foo", "bar"));
assertEquals(1, found.size());
assertEquals(id3, found.getResources(0, 1).get(0).getIdElement());
}
{
IBundleProvider found = myObservationDao.search(Observation.SP_VALUE_QUANTITY, new QuantityParam("ne123", "foo", "bar"));
assertEquals(0, found.size());
}
}
@Test
@ -1715,7 +1826,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
assertEquals(1, found.size());
found = toList(myObservationDao.search("value-quantity", new QuantityParam(112)));
assertEquals(1, found.size());
assertEquals(0, found.size());
found = toList(myObservationDao.search("value-quantity", new QuantityParam(212)));
assertEquals(0, found.size());

View File

@ -40,6 +40,10 @@ import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.hl7.fhir.dstu3.model.BaseResource;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.dstu3.model.Bundle.BundleType;
import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb;
import org.hl7.fhir.dstu3.model.Bundle.SearchEntryMode;
import org.hl7.fhir.dstu3.model.Coding;
import org.hl7.fhir.dstu3.model.Condition;
import org.hl7.fhir.dstu3.model.DateTimeType;
@ -48,8 +52,11 @@ import org.hl7.fhir.dstu3.model.Device;
import org.hl7.fhir.dstu3.model.DiagnosticOrder;
import org.hl7.fhir.dstu3.model.DocumentManifest;
import org.hl7.fhir.dstu3.model.DocumentReference;
import org.hl7.fhir.dstu3.model.DomainResource;
import org.hl7.fhir.dstu3.model.Encounter;
import org.hl7.fhir.dstu3.model.Encounter.EncounterClass;
import org.hl7.fhir.dstu3.model.Encounter.EncounterLocationComponent;
import org.hl7.fhir.dstu3.model.Encounter.EncounterState;
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.ImagingStudy;
import org.hl7.fhir.dstu3.model.InstantType;
@ -57,6 +64,7 @@ import org.hl7.fhir.dstu3.model.Location;
import org.hl7.fhir.dstu3.model.Medication;
import org.hl7.fhir.dstu3.model.MedicationOrder;
import org.hl7.fhir.dstu3.model.Meta;
import org.hl7.fhir.dstu3.model.Narrative.NarrativeStatus;
import org.hl7.fhir.dstu3.model.Observation;
import org.hl7.fhir.dstu3.model.Organization;
import org.hl7.fhir.dstu3.model.Parameters;
@ -64,37 +72,27 @@ import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.Period;
import org.hl7.fhir.dstu3.model.Practitioner;
import org.hl7.fhir.dstu3.model.Questionnaire;
import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemType;
import org.hl7.fhir.dstu3.model.QuestionnaireResponse;
import org.hl7.fhir.dstu3.model.Reference;
import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.dstu3.model.Subscription;
import org.hl7.fhir.dstu3.model.TemporalPrecisionEnum;
import org.hl7.fhir.dstu3.model.UnsignedIntType;
import org.hl7.fhir.dstu3.model.UriType;
import org.hl7.fhir.dstu3.model.ValueSet;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.dstu3.model.Bundle.BundleType;
import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb;
import org.hl7.fhir.dstu3.model.Bundle.SearchEntryMode;
import org.hl7.fhir.dstu3.model.Encounter.EncounterClass;
import org.hl7.fhir.dstu3.model.Encounter.EncounterLocationComponent;
import org.hl7.fhir.dstu3.model.Encounter.EncounterState;
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
import org.hl7.fhir.dstu3.model.Narrative.NarrativeStatus;
import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemType;
import org.hl7.fhir.dstu3.model.Subscription.SubscriptionChannelType;
import org.hl7.fhir.dstu3.model.Subscription.SubscriptionStatus;
import org.hl7.fhir.dstu3.model.TemporalPrecisionEnum;
import org.hl7.fhir.dstu3.model.UnsignedIntType;
import org.hl7.fhir.dstu3.model.ValueSet;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.Ignore;
import org.junit.Test;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.IGenericClient;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.StringOrListParam;
import ca.uhn.fhir.rest.param.StringParam;
@ -1764,6 +1762,45 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
//@formatter:on
}
@Test()
public void testSearchWithInvalidQuantityPrefix() throws Exception {
Observation o = new Observation();
o.getCode().setText("testSearchWithInvalidSort");
myObservationDao.create(o);
try {
//@formatter:off
ourClient
.search()
.forResource(Observation.class)
.where(Observation.VALUE_QUANTITY.withPrefix(ParamPrefixEnum.ENDS_BEFORE).number(100).andNoUnits())
.prettyPrint()
.returnBundle(Bundle.class)
.execute();
//@formatter:on
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("Unable to handle quantity prefix \"eb\" for value: eb100||"));
}
}
@Test()
public void testSearchWithInvalidNumberPrefix() throws Exception {
try {
//@formatter:off
ourClient
.search()
.forResource(Encounter.class)
.where(Encounter.LENGTH.withPrefix(ParamPrefixEnum.ENDS_BEFORE).number(100))
.prettyPrint()
.returnBundle(Bundle.class)
.execute();
//@formatter:on
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("Unable to handle number prefix \"eb\" for value: eb100"));
}
}
@Test
public void testSearchWithMissing() throws Exception {
ourLog.info("Starting testSearchWithMissing");

View File

@ -4,10 +4,13 @@ import static org.junit.Assert.*;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dstu.composite.CodingDt;
public class CodingDtTest {
private static FhirContext ourCtx = FhirContext.forDstu1();
@Test
public void testTokenNoSystem() {
CodingDt dt = new CodingDt();
@ -15,7 +18,7 @@ public class CodingDtTest {
assertEquals(null, dt.getSystem().getValueAsString());
assertEquals("c", dt.getCode().getValue());
assertEquals("c", dt.getValueAsQueryToken());
assertEquals("c", dt.getValueAsQueryToken(ourCtx));
}
@Test
@ -25,7 +28,7 @@ public class CodingDtTest {
assertEquals("a", dt.getSystem().getValueAsString());
assertEquals("b|c", dt.getCode().getValue());
assertEquals("a|b\\|c", dt.getValueAsQueryToken());
assertEquals("a|b\\|c", dt.getValueAsQueryToken(ourCtx));
}
@Test
@ -36,7 +39,7 @@ public class CodingDtTest {
assertEquals("", dt.getSystem().getValueAsString());
assertEquals("b|c", dt.getCode().getValue());
assertEquals("|b\\|c", dt.getValueAsQueryToken());
assertEquals("|b\\|c", dt.getValueAsQueryToken(ourCtx));
}
/**
@ -50,6 +53,6 @@ public class CodingDtTest {
assertEquals("", dt.getSystem().getValueAsString());
assertEquals("b|c", dt.getCode().getValue());
assertEquals("|b\\|c", dt.getValueAsQueryToken());
assertEquals("|b\\|c", dt.getValueAsQueryToken(ourCtx));
}
}

View File

@ -4,10 +4,12 @@ import static org.junit.Assert.*;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
public class IdentifierDtTest {
private static FhirContext ourCtx = FhirContext.forDstu1();
@Test
public void testTokenNoSystem() {
IdentifierDt dt = new IdentifierDt();
@ -15,7 +17,7 @@ public class IdentifierDtTest {
assertEquals(null, dt.getSystem().getValueAsString());
assertEquals("c", dt.getValue().getValue());
assertEquals("c", dt.getValueAsQueryToken());
assertEquals("c", dt.getValueAsQueryToken(ourCtx));
}
@Test
@ -25,7 +27,7 @@ public class IdentifierDtTest {
assertEquals("a", dt.getSystem().getValueAsString());
assertEquals("b|c", dt.getValue().getValue());
assertEquals("a|b\\|c", dt.getValueAsQueryToken());
assertEquals("a|b\\|c", dt.getValueAsQueryToken(ourCtx));
}
@Test
@ -36,7 +38,7 @@ public class IdentifierDtTest {
assertEquals("", dt.getSystem().getValueAsString());
assertEquals("b|c", dt.getValue().getValue());
assertEquals("|b\\|c", dt.getValueAsQueryToken());
assertEquals("|b\\|c", dt.getValueAsQueryToken(ourCtx));
}
/**
@ -50,7 +52,7 @@ public class IdentifierDtTest {
assertEquals("", dt.getSystem().getValueAsString());
assertEquals("b|c", dt.getValue().getValue());
assertEquals("|b\\|c", dt.getValueAsQueryToken());
assertEquals("|b\\|c", dt.getValueAsQueryToken(ourCtx));
}

View File

@ -4,19 +4,21 @@ import static org.junit.Assert.*;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
public class QuantityParamTest {
private static FhirContext ourCtx = FhirContext.forDstu1();
@Test
public void testFull() {
QuantityParam p = new QuantityParam();
p.setValueAsQueryToken(null, "<5.4|http://unitsofmeasure.org|mg");
assertEquals(QuantityCompararatorEnum.LESSTHAN,p.getComparator());
assertEquals("5.4", p.getValue().getValueAsString());
assertEquals("http://unitsofmeasure.org", p.getSystem().getValueAsString());
assertEquals("5.4", p.getValue().toPlainString());
assertEquals("http://unitsofmeasure.org", p.getSystem());
assertEquals("mg", p.getUnits());
assertEquals("<5.4|http://unitsofmeasure.org|mg", p.getValueAsQueryToken());
assertEquals("<5.4|http://unitsofmeasure.org|mg", p.getValueAsQueryToken(ourCtx));
}
@Test
@ -25,10 +27,10 @@ public class QuantityParamTest {
p.setValueAsQueryToken(null, "~5.4|http://unitsofmeasure.org|mg");
assertEquals(null,p.getComparator());
assertEquals(true, p.isApproximate());
assertEquals("5.4", p.getValue().getValueAsString());
assertEquals("http://unitsofmeasure.org", p.getSystem().getValueAsString());
assertEquals("5.4", p.getValue().toPlainString());
assertEquals("http://unitsofmeasure.org", p.getSystem());
assertEquals("mg", p.getUnits());
assertEquals("~5.4|http://unitsofmeasure.org|mg", p.getValueAsQueryToken());
assertEquals("~5.4|http://unitsofmeasure.org|mg", p.getValueAsQueryToken(ourCtx));
}
@ -37,10 +39,10 @@ public class QuantityParamTest {
QuantityParam p = new QuantityParam();
p.setValueAsQueryToken(null, "5.4|http://unitsofmeasure.org|mg");
assertEquals(null, p.getComparator());
assertEquals("5.4", p.getValue().getValueAsString());
assertEquals("http://unitsofmeasure.org", p.getSystem().getValueAsString());
assertEquals("5.4", p.getValue().toPlainString());
assertEquals("http://unitsofmeasure.org", p.getSystem());
assertEquals("mg", p.getUnits());
assertEquals("5.4|http://unitsofmeasure.org|mg", p.getValueAsQueryToken());
assertEquals("5.4|http://unitsofmeasure.org|mg", p.getValueAsQueryToken(ourCtx));
}
@ -49,10 +51,10 @@ public class QuantityParamTest {
QuantityParam p = new QuantityParam();
p.setValueAsQueryToken(null, "5.4");
assertEquals(null, p.getComparator());
assertEquals("5.4", p.getValue().getValueAsString());
assertEquals(null, p.getSystem().getValueAsString());
assertEquals("5.4", p.getValue().toPlainString());
assertEquals(null, p.getSystem());
assertEquals(null, p.getUnits());
assertEquals("5.4||", p.getValueAsQueryToken());
assertEquals("5.4||", p.getValueAsQueryToken(ourCtx));
}
}

View File

@ -228,8 +228,8 @@ public class ReferenceParameterTest {
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals("foo|bar", ourLastRefParam.getValue());
assertEquals("foo", ourLastRefParam.toTokenParam().getSystem());
assertEquals("bar", ourLastRefParam.toTokenParam().getValue());
assertEquals("foo", ourLastRefParam.toTokenParam(ourCtx).getSystem());
assertEquals("bar", ourLastRefParam.toTokenParam(ourCtx).getValue());
}
@ -427,7 +427,7 @@ public class ReferenceParameterTest {
Patient p = new Patient();
p.setId("1");
p.addName().addFamily("0" + theParam.getValueAsQueryToken());
p.addName().addFamily("0" + theParam.getValueAsQueryToken(ourCtx));
p.addName().addFamily("1" + defaultString(theParam.getResourceType()));
p.addName().addFamily("2" + defaultString(theParam.getChain()));
retVal.add(p);

View File

@ -85,11 +85,7 @@ import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.provider.ServerProfileProvider;
import ca.uhn.fhir.util.PortUtil;
/**
* Created by dsotnikov on 2/25/2014.
*/
public class RestfulServerMethodTest {
private static CloseableHttpClient ourClient;
private static final FhirContext ourCtx = FhirContext.forDstu1();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestfulServerMethodTest.class);
@ -722,8 +718,8 @@ public class RestfulServerMethodTest {
assertEquals(1, bundle.getEntries().size());
Patient patient = (Patient) bundle.getEntries().get(0).getResource();
assertEquals("urn:aaa|aaa", patient.getIdentifier().get(1).getValueAsQueryToken());
assertEquals("urn:bbb|bbb", patient.getIdentifier().get(2).getValueAsQueryToken());
assertEquals("urn:aaa|aaa", patient.getIdentifier().get(1).getValueAsQueryToken(ourCtx));
assertEquals("urn:bbb|bbb", patient.getIdentifier().get(2).getValueAsQueryToken(ourCtx));
}
@Test
@ -1256,8 +1252,8 @@ public class RestfulServerMethodTest {
@Search()
public Patient getPatientByDateRange(@RequiredParam(name = "dateRange") DateRangeParam theIdentifiers) {
Patient retVal = getIdToPatient().get("1");
retVal.getName().get(0).addSuffix().setValue(theIdentifiers.getLowerBound().getValueAsQueryToken());
retVal.getName().get(0).addSuffix().setValue(theIdentifiers.getUpperBound().getValueAsQueryToken());
retVal.getName().get(0).addSuffix().setValue(theIdentifiers.getLowerBound().getValueAsQueryToken(ourCtx));
retVal.getName().get(0).addSuffix().setValue(theIdentifiers.getUpperBound().getValueAsQueryToken(ourCtx));
return retVal;
}

View File

@ -18,6 +18,7 @@ package ca.uhn.fhir.testmodel;
import java.util.List;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.BaseIdentifiableElement;
import ca.uhn.fhir.model.api.ICompositeDatatype;
import ca.uhn.fhir.model.api.IElement;
@ -376,7 +377,7 @@ public class IdentifierDt
* {@inheritDoc}
*/
@Override
public String getValueAsQueryToken() {
public String getValueAsQueryToken(FhirContext theContext) {
if (org.apache.commons.lang3.StringUtils.isNotBlank(getSystem().getValueAsString())) {
return getSystem().getValueAsString() + '|' + getValue().getValueAsString();
} else {

View File

@ -4,7 +4,10 @@ import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.either;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -22,7 +25,6 @@ import org.apache.http.Header;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
@ -1786,7 +1788,7 @@ public class GenericClientDstu2Test {
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient?name=james&_lastUpdated=%3E%3D2011-01-01&_lastUpdated=%3C%3D2012-01-01", capt.getValue().getURI().toString());
assertEquals("http://example.com/fhir/Patient?name=james&_lastUpdated=ge2011-01-01&_lastUpdated=le2012-01-01", capt.getValue().getURI().toString());
assertEquals(Patient.class, response.getEntries().get(0).getResource().getClass());
}

View File

@ -36,6 +36,7 @@ import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
@ -52,7 +53,7 @@ public class FhirInstanceValidatorDstu3Test {
private static FhirContext ourCtx = FhirContext.forDstu3();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirInstanceValidatorDstu3Test.class);
private DefaultProfileValidationSupport myDefaultValidationSupport = new DefaultProfileValidationSupport();
private static DefaultProfileValidationSupport myDefaultValidationSupport = new DefaultProfileValidationSupport();
private FhirInstanceValidator myInstanceVal;
private IValidationSupport myMockSupport;
@ -66,9 +67,10 @@ public class FhirInstanceValidatorDstu3Test {
myValidConcepts.add(theSystem + "___" + theCode);
}
@After
public void after() {
@AfterClass
public static void afterClass() {
myDefaultValidationSupport.flush();
myDefaultValidationSupport = null;
}
@SuppressWarnings("unchecked")

View File

@ -101,7 +101,7 @@ public class ${className}
@Override
public String toString() {
return "IdentifierDt[" + getValueAsQueryToken() + "]";
return "IdentifierDt[" + getValue() + "]";
}
#end
#if ( ${className} == "QuantityDt" )

View File

@ -111,7 +111,7 @@ public class ${className}
@Override
public String toString() {
return "IdentifierDt[" + getValueAsQueryToken() + "]";
return "IdentifierDt[" + getValue() + "]";
}
#end
#if ( ${className} == "QuantityDt" )

20
pom.xml
View File

@ -244,8 +244,8 @@
<jetty_version>9.3.7.v20160115 </jetty_version>
<!-- Note on Hibernate versions: Hibernate 4.3+ uses JPA 2.1, which is too new for a number of platforms including JBoss EAP 6.x and Glassfish 3.0. Upgrade this version with caution! Also note that if
you change this, you may get a failure in hibernate4-maven-plugin. See the note in hapi-fhir-jpaserver-base/pom.xml's configuration for that plugin... -->
<hibernate_version>5.0.7.Final</hibernate_version>
<hibernate_validator_version>5.2.2.Final</hibernate_validator_version>
<hibernate_version>5.1.0.Final</hibernate_version>
<hibernate_validator_version>5.2.3.Final</hibernate_validator_version>
<maven_assembly_plugin_version>2.5.3</maven_assembly_plugin_version>
<maven_license_plugin_version>1.8</maven_license_plugin_version>
<maven_site_plugin_version>3.4</maven_site_plugin_version>
@ -404,7 +404,7 @@
<dependency>
<groupId>org.apache.maven.doxia</groupId>
<artifactId>doxia-module-markdown</artifactId>
<version>1.6</version>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.apache.maven.scm</groupId>
@ -564,17 +564,17 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-android</artifactId>
<version>1.7.14</version>
<version>1.7.16</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.14</version>
<version>1.7.16</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.14</version>
<version>1.7.16</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
@ -675,7 +675,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5</version>
<version>3.5.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
@ -687,7 +687,7 @@
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
<version>2.0.7</version>
<version>2.0.8</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
@ -956,7 +956,7 @@
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>6.14.1</version>
<version>6.15</version>
</dependency>
</dependencies>
<configuration>
@ -1263,7 +1263,7 @@
<dependency>
<groupId>org.apache.maven.doxia</groupId>
<artifactId>doxia-module-markdown</artifactId>
<version>1.6</version>
<version>1.7</version>
</dependency>
<dependency>
<groupId>lt.velykis.maven.skins</groupId>

View File

@ -12,9 +12,7 @@
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>restful-server-example</artifactId>
<version>1.5-SNAPSHOT</version>
<packaging>war</packaging>
<name>HAPI FHIR Sample RESTful Server</name>
@ -64,19 +62,23 @@
HAPI-FHIR uses Logback for logging support. The logback library is included
automatically by Maven as a part of the hapi-fhir-base dependency, but you
also need to include a logging library. Logback is used here, but log4j
would also be fine.
would also be fine.
Note on Dependency Versions: This POM file inherits
versions (<version>1.0</version>) in each dependency and plugin
from the parent pom.xml file. If you want to use this POM as the basis
for your own project, you'll need to manually add versions to the
dependencies below.
-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.2</version>
</dependency>
<!-- Needed for JEE/Servlet support -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
@ -87,14 +89,12 @@
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
<!-- Used for CORS support -->
<dependency>
<groupId>org.ebaysf.web</groupId>
<artifactId>cors-filter</artifactId>
<version>1.0.1</version>
<exclusions>
<exclusion>
<artifactId>servlet-api</artifactId>
@ -124,7 +124,6 @@
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.1.1.v20140108</version>
</plugin>
</plugins>
</pluginManagement>
@ -136,7 +135,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
@ -150,7 +148,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<overlays>
<overlay>
@ -168,7 +165,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<configuration>
<skip>false</skip>
</configuration>

View File

@ -10,6 +10,7 @@ import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
import ca.uhn.fhir.narrative.INarrativeGenerator;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
/**
* This servlet is the actual FHIR server itself
@ -49,11 +50,17 @@ public class ExampleRestfulServlet extends RestfulServer {
getFhirContext().setNarrativeGenerator(narrativeGen);
/*
* Tells HAPI to use content types which are not technically FHIR compliant when a browser is detected as the
* requesting client. This prevents browsers from trying to download resource responses instead of displaying them
* inline which can be handy for troubleshooting.
* This server interceptor causes the server to return nicely
* formatter and coloured responses instead of plain JSON/XML if
* the request is coming from a browser window. It is optional,
* but can be nice for testing.
*/
setUseBrowserFriendlyContentTypes(true);
registerInterceptor(new ResponseHighlighterInterceptor());
/*
* Tells the server to return pretty-printed responses by default
*/
setDefaultPrettyPrint(true);
}

View File

@ -7,11 +7,15 @@
</properties>
<body>
<release version="1.5" date="TBD">
<action type="fix" issue="291">
Fix a failure starting the REST server if a method returns an untyped List, which
among other things prevented resource provider added to the server
as CDI beans in a JBoss enviroment. Thanks to GitHub user fw060 (Fei) for
reporting and figuring out exactly why this wasn't working!
<action type="add">
Bump the version of a few dependencies to the
latest versions (dependent HAPI modules listed in brackets):
<![CDATA[
<ul>
<li>Hibernate (JPA, Web Tester): 5.0.7 -&gt; 5.1.0</li>
<li>SLF4j (All): 1.7.14 -&gt; 1.7.16</li>
</ul>
]]>
</action>
<action type="add">
Support comments when parsing and encoding both JSON and XML. Comments are retrieved
@ -24,6 +28,37 @@
the downloaded content file, or use an arbitrary one. Thanks to Adam Carbone
for the pull request!
</action>
<action type="fix">
REST search parameters with a prefix/comparator had not been updated to use
the DSTU2 style prefixes (gt2011-01-10) instead of the DSTU1 style prefixes
(&gt;2011-01-01). The client has been updated so that it uses the new prefixes
if the client has a DSTU2+ context. The server has been updated so that it now
supports both styles.
<![CDATA[<br/><br/>]]>
As a part of this change, a new enum called
<![CDATA[<a href="./apidocs/ca/uhn/fhir/rest/param/ParamPrefixEnum.html">ParamPrefixEnum</a>]]
has been introduced. This enum replaces the old
<![CDATA[<a href="./apidocs/ca/uhn/fhir/model/dstu/valueset/QuantityCompararatorEnum.html">QuantityCompararatorEnum</a>]]>
which has a typo in its name and can not represent several new prefixes added since
DSTU1.
</action>
<action type="add">
JPA server number and quantity search params now follow the rules for the
use of precision in search terms outlined in the
<![CDATA[<a href="https://www.hl7.org/fhir/search.html">search page</a>]]> of the
FHIR specification. For example, previously a 1% tolerance was applied for
all searches (10% for approximate search). Now, a tolerance which respects the
precision of the search term is used (but still 10% for approximate search).
</action>
<action type="fix" issue="291">
Fix a failure starting the REST server if a method returns an untyped List, which
among other things prevented resource provider added to the server
as CDI beans in a JBoss enviroment. Thanks to GitHub user fw060 (Fei) for
reporting and figuring out exactly why this wasn't working!
</action>
<action type="add">
JPA server now supports :above and :below qualifiers on URI search params
</action>
</release>
<release version="1.4" date="2016-02-04">
<action type="add">

View File

@ -45,9 +45,9 @@
annotated with special annotations indicating which RESTful operation
that method supports. Below is a simple example of a resource provider
which supports the
<a href="http://hl7.org/implement/standards/fhir/http.html#read">read</a>
<a href="http://hl7.org/fhir/http.html#read">read</a>
operation (i.e. retrieve a single resource by ID) as well as the
<a href="http://hl7.org/implement/standards/fhir/http.html#search">search</a>
<a href="http://hl7.org/fhir/http.html#search">search</a>
operation (i.e. find any resources matching a given criteria) for a specific
search criteria.
</p>
@ -66,6 +66,12 @@
<a href="./doc_rest_operations.html">RESTful Operations</a> for
lots more examples of how to add methods for various operations.
</p>
<p>
For now, we will move on to the next step though, which is creating
the actual server to hold your resource providers and deploying that.
Once you have this working, you might want to come back and
start adding other operations.
</p>
</subsection>