Work on support for _at parameter in history operation
This commit is contained in:
parent
23550240ad
commit
1166a2ee67
|
@ -34,6 +34,7 @@ import ca.uhn.fhir.model.primitive.IdDt;
|
|||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.annotation.AddTags;
|
||||
import ca.uhn.fhir.rest.annotation.At;
|
||||
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
|
||||
import ca.uhn.fhir.rest.annotation.Count;
|
||||
import ca.uhn.fhir.rest.annotation.Create;
|
||||
|
@ -363,7 +364,11 @@ public void deletePatientConditional(@IdParam IdDt theId, @ConditionalUrlParam S
|
|||
|
||||
//START SNIPPET: history
|
||||
@History()
|
||||
public List<Patient> getPatientHistory(@IdParam IdDt theId) {
|
||||
public List<Patient> getPatientHistory(
|
||||
@IdParam IdDt theId,
|
||||
@Since InstantDt theSince,
|
||||
@At DateRangeParam theAt
|
||||
) {
|
||||
List<Patient> retVal = new ArrayList<Patient>();
|
||||
|
||||
Patient patient = new Patient();
|
||||
|
|
|
@ -21,17 +21,25 @@ package ca.uhn.fhir.context;
|
|||
*/
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseDatatype;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
|
||||
import ca.uhn.fhir.model.api.BasePrimitive;
|
||||
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
|
||||
public class RuntimePrimitiveDatatypeDefinition extends BaseRuntimeElementDefinition<IPrimitiveType<?>> implements IRuntimeDatatypeDefinition {
|
||||
|
||||
private Class<?> myNativeType;
|
||||
private BaseRuntimeElementDefinition<?> myProfileOf;
|
||||
private Class<? extends IBaseDatatype> myProfileOfType;
|
||||
private boolean mySpecialization;
|
||||
|
@ -49,6 +57,30 @@ public class RuntimePrimitiveDatatypeDefinition extends BaseRuntimeElementDefini
|
|||
if (myProfileOfType.equals(IBaseDatatype.class)) {
|
||||
myProfileOfType = null;
|
||||
}
|
||||
|
||||
determineNativeType(theImplementingClass);
|
||||
}
|
||||
|
||||
private void determineNativeType(Class<? extends IPrimitiveType<?>> theImplementingClass) {
|
||||
Class<?> clazz = theImplementingClass;
|
||||
while (clazz.equals(Object.class) == false) {
|
||||
Type type = clazz.getGenericSuperclass();
|
||||
if (type instanceof ParameterizedType) {
|
||||
ParameterizedType superPt = (ParameterizedType) type;
|
||||
Type rawType = superPt.getRawType();
|
||||
if (rawType instanceof Class) {
|
||||
Class<?> rawClass = (Class<?>) rawType;
|
||||
if (rawClass.getName().endsWith(".BasePrimitive") || rawClass.getName().endsWith(".PrimitiveType")) {
|
||||
Type typeVariable = superPt.getActualTypeArguments()[0];
|
||||
if (typeVariable instanceof Class) {
|
||||
myNativeType = (Class<?>) typeVariable;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -56,11 +88,27 @@ public class RuntimePrimitiveDatatypeDefinition extends BaseRuntimeElementDefini
|
|||
return ChildTypeEnum.PRIMITIVE_DATATYPE;
|
||||
}
|
||||
|
||||
public Class<?> getNativeType() {
|
||||
return myNativeType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends IBaseDatatype> getProfileOf() {
|
||||
return myProfileOfType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProfileOf(Class<? extends IBaseDatatype> theType) {
|
||||
if (myProfileOfType != null) {
|
||||
if (myProfileOfType.equals(theType)) {
|
||||
return true;
|
||||
} else if (myProfileOf instanceof IRuntimeDatatypeDefinition) {
|
||||
return ((IRuntimeDatatypeDefinition) myProfileOf).isProfileOf(theType);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSpecialization() {
|
||||
return mySpecialization;
|
||||
|
@ -85,17 +133,4 @@ public class RuntimePrimitiveDatatypeDefinition extends BaseRuntimeElementDefini
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProfileOf(Class<? extends IBaseDatatype> theType) {
|
||||
if (myProfileOfType != null) {
|
||||
if (myProfileOfType.equals(theType)) {
|
||||
return true;
|
||||
} else if (myProfileOf instanceof IRuntimeDatatypeDefinition) {
|
||||
return ((IRuntimeDatatypeDefinition) myProfileOf).isProfileOf(theType);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -105,10 +105,10 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
|||
leftPadWithZeros(cal.get(Calendar.SECOND), 2, b);
|
||||
if (myPrecision.ordinal() > TemporalPrecisionEnum.SECOND.ordinal()) {
|
||||
b.append('.');
|
||||
b.append(myFractionalSeconds);
|
||||
for (int i = myFractionalSeconds.length(); i < 3; i++) {
|
||||
b.append('0');
|
||||
}
|
||||
b.append(myFractionalSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,6 +179,21 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
|||
return myTimeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this object as a {@link GregorianCalendar}
|
||||
*/
|
||||
public GregorianCalendar getValueAsCalendar() {
|
||||
if (getValue() == null) {
|
||||
return null;
|
||||
}
|
||||
GregorianCalendar cal = new GregorianCalendar();
|
||||
cal.setTime(getValue());
|
||||
if (getTimeZone() != null) {
|
||||
cal.setTimeZone(getTimeZone());
|
||||
}
|
||||
return cal;
|
||||
}
|
||||
|
||||
/**
|
||||
* To be implemented by subclasses to indicate whether the given precision is allowed by this type
|
||||
*/
|
||||
|
@ -212,6 +227,7 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
|||
Calendar cal = new GregorianCalendar(0, 0, 0);
|
||||
cal.setTimeZone(TimeZone.getDefault());
|
||||
String value = theValue;
|
||||
boolean fractionalSecondsSet = false;
|
||||
|
||||
if (value.length() > 0 && (value.charAt(0) == ' ' || value.charAt(value.length()-1) == ' ')) {
|
||||
value = value.trim();
|
||||
|
@ -279,6 +295,7 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
|||
String millisString;
|
||||
if (endIndex > 23) {
|
||||
myFractionalSeconds = value.substring(20, endIndex);
|
||||
fractionalSecondsSet = true;
|
||||
endIndex = 23;
|
||||
millisString = value.substring(20, endIndex);
|
||||
millis = parseInt(value, millisString, 0, 999);
|
||||
|
@ -286,6 +303,7 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
|||
millisString = value.substring(20, endIndex);
|
||||
millis = parseInt(value, millisString, 0, 999);
|
||||
myFractionalSeconds = millisString;
|
||||
fractionalSecondsSet = true;
|
||||
}
|
||||
if (millisString.length() == 1) {
|
||||
millis = millis * 100;
|
||||
|
@ -304,6 +322,10 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
|||
cal.set(Calendar.DATE, 1);
|
||||
}
|
||||
|
||||
if (fractionalSecondsSet == false) {
|
||||
myFractionalSeconds = "";
|
||||
}
|
||||
|
||||
setPrecision(precision);
|
||||
return cal.getTime();
|
||||
|
||||
|
@ -395,11 +417,11 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
|||
public void setValue(Date theValue, TemporalPrecisionEnum thePrecision) throws DataFormatException {
|
||||
setTimeZone(TimeZone.getDefault());
|
||||
myPrecision = thePrecision;
|
||||
super.setValue(theValue);
|
||||
myFractionalSeconds = "";
|
||||
if (theValue != null) {
|
||||
myFractionalSeconds = Integer.toString((int) (theValue.getTime() % 1000));
|
||||
}
|
||||
super.setValue(theValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -468,6 +490,7 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private void validateLengthIsAtLeast(String theValue, int theLength) {
|
||||
if (theValue.length() < theLength) {
|
||||
throwBadDateFormat(theValue);
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
package ca.uhn.fhir.rest.annotation;
|
||||
|
||||
/*
|
||||
* #%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.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import ca.uhn.fhir.rest.param.DateParam;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
|
||||
/**
|
||||
* Parameter annotation for the _at parameter, which indicates to the
|
||||
* server that only results dated since the given instant will be returned.
|
||||
* <p>
|
||||
* Parameters with this annotation should be of type {@link DateParam} or {@link DateRangeParam}
|
||||
* </p>
|
||||
* @see History
|
||||
*/
|
||||
@Target(value=ElementType.PARAMETER)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface At {
|
||||
//nothing
|
||||
}
|
|
@ -25,9 +25,15 @@ import java.lang.annotation.Retention;
|
|||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import ca.uhn.fhir.rest.param.DateParam;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
|
||||
/**
|
||||
* Parameter annotation for the _since parameter, which indicates to the
|
||||
* server that only results dated since the given instant will be returned.
|
||||
* <p>
|
||||
* Parameters with this annotation should be of type {@link DateParam} or {@link DateRangeParam}
|
||||
* </p>
|
||||
*
|
||||
* @see History
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package ca.uhn.fhir.rest.method;
|
||||
|
||||
import ca.uhn.fhir.rest.annotation.At;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
|
||||
class AtParameter extends SinceOrAtParameter {
|
||||
|
||||
public AtParameter() {
|
||||
super(Constants.PARAM_AT, At.class);
|
||||
}
|
||||
|
||||
}
|
|
@ -38,6 +38,7 @@ class BaseBinder<T> {
|
|||
myType = theType;
|
||||
myCompositeTypes = theCompositeTypes;
|
||||
|
||||
|
||||
if (myType.equals(CompositeParam.class)) {
|
||||
if (myCompositeTypes.size() != 2) {
|
||||
throw new ConfigurationException("Search parameter of type " + myType.getName() + " must have 2 composite types declared in parameter annotation, found " + theCompositeTypes.size());
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package ca.uhn.fhir.rest.method;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterOr;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
abstract class BaseJavaPrimitiveBinder<T>implements IParamBinder<T> {
|
||||
|
||||
public BaseJavaPrimitiveBinder() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected abstract String doEncode(T theString);
|
||||
|
||||
protected abstract T doParse(String theString);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public List<IQueryParameterOr<?>> encode(FhirContext theContext, T theString) throws InternalErrorException {
|
||||
String retVal = doEncode(theString);
|
||||
if (isBlank(retVal)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<?> retValList = Collections.singletonList(MethodUtil.singleton(new StringParam(retVal)));
|
||||
return (List<IQueryParameterOr<?>>) retValList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T parse(String theName, List<QualifiedParamList> theParams) throws InternalErrorException, InvalidRequestException {
|
||||
if (theParams.size() == 0 || theParams.get(0).size() == 0) {
|
||||
return null;
|
||||
}
|
||||
if (theParams.size() > 1 || theParams.get(0).size() > 1) {
|
||||
throw new InvalidRequestException("Multiple values detected for non-repeatable parameter '" + theName + "'. This server is not configured to allow multiple (AND) values for this param.");
|
||||
}
|
||||
|
||||
T value = doParse(theParams.get(0).get(0));
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package ca.uhn.fhir.rest.method;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
|
||||
final class CalendarBinder extends BaseJavaPrimitiveBinder<Calendar> {
|
||||
CalendarBinder() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doEncode(Calendar theString) {
|
||||
return new InstantDt(theString).getValueAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Calendar doParse(String theString) {
|
||||
return new InstantDt(theString).getValueAsCalendar();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package ca.uhn.fhir.rest.method;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
|
||||
final class DateBinder extends BaseJavaPrimitiveBinder<Date> {
|
||||
DateBinder() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doEncode(Date theString) {
|
||||
return new InstantDt(theString).getValueAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Date doParse(String theString) {
|
||||
return new InstantDt(theString).getValue();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package ca.uhn.fhir.rest.method;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
|
||||
import ca.uhn.fhir.util.ReflectionUtil;
|
||||
|
||||
final class FhirPrimitiveBinder extends BaseJavaPrimitiveBinder<IPrimitiveType<?>> {
|
||||
|
||||
private Class<IPrimitiveType<?>> myType;
|
||||
|
||||
FhirPrimitiveBinder(Class<IPrimitiveType<?>> theType) {
|
||||
myType = theType;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doEncode(IPrimitiveType<?> theString) {
|
||||
return theString.getValueAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IPrimitiveType<?> doParse(String theString) {
|
||||
IPrimitiveType<?> instance = ReflectionUtil.newInstance(myType);
|
||||
instance.setValueAsString(theString);
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -29,7 +29,7 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
|||
|
||||
interface IParamBinder<T> {
|
||||
|
||||
List<IQueryParameterOr<?>> encode(FhirContext theContext, Object theString) throws InternalErrorException;
|
||||
List<IQueryParameterOr<?>> encode(FhirContext theContext, T theString) throws InternalErrorException;
|
||||
|
||||
T parse(String theName, List<QualifiedParamList> theList) throws InternalErrorException, InvalidRequestException;
|
||||
|
||||
|
|
|
@ -45,11 +45,11 @@ import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
|||
import ca.uhn.fhir.model.api.Tag;
|
||||
import ca.uhn.fhir.model.api.TagList;
|
||||
import ca.uhn.fhir.model.api.annotation.Description;
|
||||
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.annotation.At;
|
||||
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
|
||||
import ca.uhn.fhir.rest.annotation.Count;
|
||||
import ca.uhn.fhir.rest.annotation.Elements;
|
||||
|
@ -112,6 +112,7 @@ import ca.uhn.fhir.util.ReflectionUtil;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class MethodUtil {
|
||||
private static final String LABEL = "label=\"";
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(MethodUtil.class);
|
||||
|
@ -360,7 +361,6 @@ public class MethodUtil {
|
|||
return MethodUtil.findParamAnnotationIndex(theMethod, TagListParam.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static Integer findVersionIdParameterIndex(Method theMethod) {
|
||||
return MethodUtil.findParamAnnotationIndex(theMethod, VersionIdParam.class);
|
||||
}
|
||||
|
@ -422,7 +422,7 @@ public class MethodUtil {
|
|||
parameter.setDeclaredTypes(((RequiredParam) nextAnnotation).targetTypes());
|
||||
parameter.setCompositeTypes(((RequiredParam) nextAnnotation).compositeTypes());
|
||||
parameter.setChainlists(((RequiredParam) nextAnnotation).chainWhitelist(), ((RequiredParam) nextAnnotation).chainBlacklist());
|
||||
parameter.setType(parameterType, innerCollectionType, outerCollectionType);
|
||||
parameter.setType(theContext, parameterType, innerCollectionType, outerCollectionType);
|
||||
MethodUtil.extractDescription(parameter, annotations);
|
||||
param = parameter;
|
||||
} else if (nextAnnotation instanceof OptionalParam) {
|
||||
|
@ -432,7 +432,7 @@ public class MethodUtil {
|
|||
parameter.setDeclaredTypes(((OptionalParam) nextAnnotation).targetTypes());
|
||||
parameter.setCompositeTypes(((OptionalParam) nextAnnotation).compositeTypes());
|
||||
parameter.setChainlists(((OptionalParam) nextAnnotation).chainWhitelist(), ((OptionalParam) nextAnnotation).chainBlacklist());
|
||||
parameter.setType(parameterType, innerCollectionType, outerCollectionType);
|
||||
parameter.setType(theContext, parameterType, innerCollectionType, outerCollectionType);
|
||||
MethodUtil.extractDescription(parameter, annotations);
|
||||
param = parameter;
|
||||
} else if (nextAnnotation instanceof IncludeParam) {
|
||||
|
@ -480,6 +480,10 @@ public class MethodUtil {
|
|||
param = new ElementsParameter();
|
||||
} else if (nextAnnotation instanceof Since) {
|
||||
param = new SinceParameter();
|
||||
((SinceParameter)param).setType(theContext, parameterType, innerCollectionType, outerCollectionType);
|
||||
} else if (nextAnnotation instanceof At) {
|
||||
param = new AtParameter();
|
||||
((AtParameter)param).setType(theContext, parameterType, innerCollectionType, outerCollectionType);
|
||||
} else if (nextAnnotation instanceof Count) {
|
||||
param = new CountParameter();
|
||||
} else if (nextAnnotation instanceof Sort) {
|
||||
|
|
|
@ -202,7 +202,7 @@ public class OperationParameter implements IParameter {
|
|||
myParamType = "string";
|
||||
mySearchParameterBinding = new SearchParameter(myName, myMin > 0);
|
||||
mySearchParameterBinding.setCompositeTypes(COMPOSITE_TYPES);
|
||||
mySearchParameterBinding.setType(theParameterType, theInnerCollectionType, theOuterCollectionType);
|
||||
mySearchParameterBinding.setType(myContext, theParameterType, theInnerCollectionType, theOuterCollectionType);
|
||||
myConverter = new QueryParameterConverter();
|
||||
} else {
|
||||
throw new ConfigurationException("Invalid type for @OperationParam: " + myParameterType.getName());
|
||||
|
|
|
@ -37,7 +37,7 @@ final class QueryParameterAndBinder extends BaseBinder<IQueryParameterAnd<?>> im
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public List<IQueryParameterOr<?>> encode(FhirContext theContext, Object theString) throws InternalErrorException {
|
||||
public List<IQueryParameterOr<?>> encode(FhirContext theContext, IQueryParameterAnd<?> theString) throws InternalErrorException {
|
||||
List<IQueryParameterOr<?>> retVal = (List<IQueryParameterOr<?>>) ((IQueryParameterAnd<?>) theString).getValuesAsQueryTokens();
|
||||
return retVal;
|
||||
}
|
||||
|
|
|
@ -37,8 +37,8 @@ final class QueryParameterOrBinder extends BaseBinder<IQueryParameterOr<?>> impl
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public List<IQueryParameterOr<?>> encode(FhirContext theContext, Object theString) throws InternalErrorException {
|
||||
IQueryParameterOr<?> retVal = ((IQueryParameterOr<?>) theString);
|
||||
public List<IQueryParameterOr<?>> encode(FhirContext theContext, IQueryParameterOr<?> theValue) throws InternalErrorException {
|
||||
IQueryParameterOr<?> retVal = (theValue);
|
||||
List<?> retVal2 = Collections.singletonList((IQueryParameterOr<?>)retVal);
|
||||
return (List<IQueryParameterOr<?>>) retVal2;
|
||||
}
|
||||
|
|
|
@ -39,8 +39,8 @@ final class QueryParameterTypeBinder extends BaseBinder<IQueryParameterType> imp
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public List<IQueryParameterOr<?>> encode(FhirContext theContext, Object theString) throws InternalErrorException {
|
||||
IQueryParameterType param = (IQueryParameterType) theString;
|
||||
public List<IQueryParameterOr<?>> encode(FhirContext theContext, IQueryParameterType theValue) throws InternalErrorException {
|
||||
IQueryParameterType param = theValue;
|
||||
List<?> retVal = Collections.singletonList(MethodUtil.singleton(param));
|
||||
return (List<IQueryParameterOr<?>>) retVal;
|
||||
}
|
||||
|
|
|
@ -22,8 +22,10 @@ package ca.uhn.fhir.rest.method;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -31,9 +33,11 @@ import java.util.Set;
|
|||
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimePrimitiveDatatypeDefinition;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterAnd;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterOr;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
|
@ -75,10 +79,8 @@ import ca.uhn.fhir.rest.server.Constants;
|
|||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.CollectionUtil;
|
||||
import ca.uhn.fhir.util.ReflectionUtil;
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class SearchParameter extends BaseQueryParameter {
|
||||
|
||||
|
@ -139,7 +141,7 @@ public class SearchParameter extends BaseQueryParameter {
|
|||
ourParamTypes.put(HasAndListParam.class, RestSearchParameterTypeEnum.HAS);
|
||||
}
|
||||
|
||||
private List<Class<? extends IQueryParameterType>> myCompositeTypes;
|
||||
private List<Class<? extends IQueryParameterType>> myCompositeTypes = Collections.emptyList();
|
||||
private List<Class<? extends IBaseResource>> myDeclaredTypes;
|
||||
private String myDescription;
|
||||
private String myName;
|
||||
|
@ -167,7 +169,12 @@ public class SearchParameter extends BaseQueryParameter {
|
|||
public List<QualifiedParamList> encode(FhirContext theContext, Object theObject) throws InternalErrorException {
|
||||
ArrayList<QualifiedParamList> retVal = new ArrayList<QualifiedParamList>();
|
||||
|
||||
List<IQueryParameterOr<?>> val = myParamBinder.encode(theContext, theObject);
|
||||
// TODO: declaring method should probably have a generic type..
|
||||
@SuppressWarnings("rawtypes")
|
||||
IParamBinder paramBinder = myParamBinder;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<IQueryParameterOr<?>> val = paramBinder.encode(theContext, theObject);
|
||||
for (IQueryParameterOr<?> nextOr : val) {
|
||||
retVal.add(new QualifiedParamList(nextOr, theContext));
|
||||
}
|
||||
|
@ -279,7 +286,7 @@ public class SearchParameter extends BaseQueryParameter {
|
|||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "unused" })
|
||||
public void setType(final Class<?> type, Class<? extends Collection<?>> theInnerCollectionType, Class<? extends Collection<?>> theOuterCollectionType) {
|
||||
public void setType(FhirContext theContext, final Class<?> type, Class<? extends Collection<?>> theInnerCollectionType, Class<? extends Collection<?>> theOuterCollectionType) {
|
||||
this.myType = type;
|
||||
if (IQueryParameterType.class.isAssignableFrom(type)) {
|
||||
myParamBinder = new QueryParameterTypeBinder((Class<? extends IQueryParameterType>) type, myCompositeTypes);
|
||||
|
@ -290,6 +297,23 @@ public class SearchParameter extends BaseQueryParameter {
|
|||
} else if (String.class.equals(type)) {
|
||||
myParamBinder = new StringBinder();
|
||||
myParamType = RestSearchParameterTypeEnum.STRING;
|
||||
} else if (Date.class.equals(type)) {
|
||||
myParamBinder = new DateBinder();
|
||||
myParamType = RestSearchParameterTypeEnum.DATE;
|
||||
} else if (Calendar.class.equals(type)) {
|
||||
myParamBinder = new CalendarBinder();
|
||||
myParamType = RestSearchParameterTypeEnum.DATE;
|
||||
} else if (IPrimitiveType.class.isAssignableFrom(type) && ReflectionUtil.isInstantiable(type)) {
|
||||
RuntimePrimitiveDatatypeDefinition def = (RuntimePrimitiveDatatypeDefinition) theContext.getElementDefinition((Class<? extends IPrimitiveType<?>>) type);
|
||||
if (def.getNativeType() != null) {
|
||||
if (def.getNativeType().equals(Date.class)) {
|
||||
myParamBinder = new FhirPrimitiveBinder((Class<IPrimitiveType<?>>) type);
|
||||
myParamType = RestSearchParameterTypeEnum.DATE;
|
||||
} else if (def.getNativeType().equals(String.class)) {
|
||||
myParamBinder = new FhirPrimitiveBinder((Class<IPrimitiveType<?>>) type);
|
||||
myParamType = RestSearchParameterTypeEnum.STRING;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new ConfigurationException("Unsupported data type for parameter: " + type.getCanonicalName());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
package ca.uhn.fhir.rest.method;
|
||||
|
||||
/*
|
||||
* #%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.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.annotation.Since;
|
||||
import ca.uhn.fhir.rest.param.ParameterUtil;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
class SinceOrAtParameter extends SearchParameter {
|
||||
|
||||
private Class<?> myType;
|
||||
private String myParamName;
|
||||
private Class<?> myAnnotationType;
|
||||
|
||||
public SinceOrAtParameter(String theParamName, Class<?> theAnnotationType) {
|
||||
super(theParamName, false);
|
||||
myParamName = theParamName;
|
||||
myAnnotationType = theAnnotationType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getQualifierBlacklist() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getQualifierWhitelist() {
|
||||
return null;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException {
|
||||
// if (theSourceClientArgument != null) {
|
||||
// InstantDt since = ParameterUtil.toInstant(theSourceClientArgument);
|
||||
// if (since.isEmpty() == false) {
|
||||
// theTargetQueryArguments.put(myParamName, Collections.singletonList(since.getValueAsString()));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
|
||||
// String[] sinceParams = theRequest.getParameters().remove(myParamName);
|
||||
// if (sinceParams != null) {
|
||||
// if (sinceParams.length > 0) {
|
||||
// if (StringUtils.isNotBlank(sinceParams[0])) {
|
||||
// try {
|
||||
// return ParameterUtil.fromInstant(myType, sinceParams);
|
||||
// } catch (DataFormatException e) {
|
||||
// throw new InvalidRequestException("Invalid " + Constants.PARAM_SINCE + " value: " + sinceParams[0]);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return ParameterUtil.fromInstant(myType, null);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
|
||||
// if (theOuterCollectionType != null) {
|
||||
// throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" + "' is annotated with @" + myAnnotationType.getName() + " but can not be of collection type");
|
||||
// }
|
||||
// if (ParameterUtil.getBindableInstantTypes().contains(theParameterType)) {
|
||||
// myType = theParameterType;
|
||||
// } else {
|
||||
// throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" + "' is annotated with @" + myAnnotationType.getName() + " but is an invalid type, must be one of: " + ParameterUtil.getBindableInstantTypes());
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
|
@ -1,85 +1,12 @@
|
|||
package ca.uhn.fhir.rest.method;
|
||||
|
||||
/*
|
||||
* #%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.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.annotation.Since;
|
||||
import ca.uhn.fhir.rest.param.ParameterUtil;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
class SinceParameter implements IParameter {
|
||||
class SinceParameter extends SinceOrAtParameter {
|
||||
|
||||
private Class<?> myType;
|
||||
|
||||
@Override
|
||||
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException {
|
||||
if (theSourceClientArgument != null) {
|
||||
InstantDt since = ParameterUtil.toInstant(theSourceClientArgument);
|
||||
if (since.isEmpty() == false) {
|
||||
theTargetQueryArguments.put(Constants.PARAM_SINCE, Collections.singletonList(since.getValueAsString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
|
||||
String[] sinceParams = theRequest.getParameters().remove(Constants.PARAM_SINCE);
|
||||
if (sinceParams != null) {
|
||||
if (sinceParams.length > 0) {
|
||||
if (StringUtils.isNotBlank(sinceParams[0])) {
|
||||
try {
|
||||
InstantDt since = new InstantDt(sinceParams[0]);
|
||||
return ParameterUtil.fromInstant(myType, since);
|
||||
} catch (DataFormatException e) {
|
||||
throw new InvalidRequestException("Invalid " + Constants.PARAM_SINCE + " value: " + sinceParams[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ParameterUtil.fromInstant(myType, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
|
||||
if (theOuterCollectionType != null) {
|
||||
throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" + "' is annotated with @" + Since.class.getName() + " but can not be of collection type");
|
||||
}
|
||||
if (!ParameterUtil.getBindableInstantTypes().contains(theParameterType)) {
|
||||
throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" + "' is annotated with @" + Since.class.getName() + " but is an invalid type, must be one of: " + ParameterUtil.getBindableInstantTypes());
|
||||
}
|
||||
myType = theParameterType;
|
||||
public SinceParameter() {
|
||||
super(Constants.PARAM_SINCE, Since.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,56 +1,18 @@
|
|||
package ca.uhn.fhir.rest.method;
|
||||
|
||||
/*
|
||||
* #%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.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterOr;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
final class StringBinder implements IParamBinder<String> {
|
||||
final class StringBinder extends BaseJavaPrimitiveBinder<String> {
|
||||
StringBinder() {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public List<IQueryParameterOr<?>> encode(FhirContext theContext, Object theString) throws InternalErrorException {
|
||||
String retVal = ((String) theString);
|
||||
List<?> retValList = Collections.singletonList(MethodUtil.singleton(new StringParam(retVal)));
|
||||
return (List<IQueryParameterOr<?>>) retValList;
|
||||
protected String doEncode(String theString) {
|
||||
return theString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parse(String theName, List<QualifiedParamList> theParams) throws InternalErrorException, InvalidRequestException {
|
||||
if (theParams.size() == 0 || theParams.get(0).size() == 0) {
|
||||
return "";
|
||||
}
|
||||
if (theParams.size() > 1 || theParams.get(0).size() > 1) {
|
||||
throw new InvalidRequestException("Multiple values detected for non-repeatable parameter '" + theName + "'. This server is not configured to allow multiple (AND) values for this param.");
|
||||
}
|
||||
|
||||
return theParams.get(0).get(0);
|
||||
protected String doParse(String theString) {
|
||||
return theString;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@ 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;
|
||||
|
|
|
@ -21,23 +21,17 @@ package ca.uhn.fhir.rest.param;
|
|||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.model.primitive.IntegerDt;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
|
||||
public class ParameterUtil {
|
||||
|
||||
private static final Set<Class<?>> BINDABLE_INTEGER_TYPES;
|
||||
private static final Set<Class<?>> BINDABLE_TIME_TYPES;
|
||||
|
||||
static {
|
||||
HashSet<Class<?>> intTypes = new HashSet<Class<?>>();
|
||||
|
@ -45,12 +39,6 @@ public class ParameterUtil {
|
|||
intTypes.add(Integer.class);
|
||||
BINDABLE_INTEGER_TYPES = Collections.unmodifiableSet(intTypes);
|
||||
|
||||
HashSet<Class<?>> timeTypes = new HashSet<Class<?>>();
|
||||
timeTypes.add(InstantDt.class);
|
||||
timeTypes.add(Date.class);
|
||||
timeTypes.add(Calendar.class);
|
||||
BINDABLE_TIME_TYPES = Collections.unmodifiableSet(timeTypes);
|
||||
|
||||
}
|
||||
|
||||
// public static Integer findSinceParameterIndex(Method theMethod) {
|
||||
|
@ -68,32 +56,11 @@ public class ParameterUtil {
|
|||
return -1;
|
||||
}
|
||||
|
||||
public static Object fromInstant(Class<?> theType, InstantDt theArgument) {
|
||||
if (theType.equals(InstantDt.class)) {
|
||||
if (theArgument == null) {
|
||||
return new InstantDt();
|
||||
}
|
||||
return theArgument;
|
||||
}
|
||||
if (theType.equals(Date.class)) {
|
||||
if (theArgument == null) {
|
||||
return null;
|
||||
}
|
||||
return theArgument.getValue();
|
||||
}
|
||||
if (theType.equals(Calendar.class)) {
|
||||
if (theArgument == null) {
|
||||
return null;
|
||||
}
|
||||
return DateUtils.toCalendar(theArgument.getValue());
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid instant type:" + theType);
|
||||
}
|
||||
|
||||
public static Object fromInteger(Class<?> theType, IntegerDt theArgument) {
|
||||
if (theType.equals(IntegerDt.class)) {
|
||||
if (theArgument == null) {
|
||||
return new IntegerDt();
|
||||
return null;
|
||||
}
|
||||
return theArgument;
|
||||
}
|
||||
|
@ -106,26 +73,10 @@ public class ParameterUtil {
|
|||
throw new IllegalArgumentException("Invalid Integer type:" + theType);
|
||||
}
|
||||
|
||||
public static Set<Class<?>> getBindableInstantTypes() {
|
||||
return BINDABLE_TIME_TYPES;
|
||||
}
|
||||
|
||||
public static Set<Class<?>> getBindableIntegerTypes() {
|
||||
return BINDABLE_INTEGER_TYPES;
|
||||
}
|
||||
|
||||
public static InstantDt toInstant(Object theArgument) {
|
||||
if (theArgument instanceof InstantDt) {
|
||||
return (InstantDt) theArgument;
|
||||
}
|
||||
if (theArgument instanceof Date) {
|
||||
return new InstantDt((Date) theArgument);
|
||||
}
|
||||
if (theArgument instanceof Calendar) {
|
||||
return new InstantDt((Calendar) theArgument);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static IntegerDt toInteger(Object theArgument) {
|
||||
if (theArgument instanceof IntegerDt) {
|
||||
|
|
|
@ -58,6 +58,8 @@ public class Constants {
|
|||
* "text/html" and "html"
|
||||
*/
|
||||
public static final Set<String> FORMATS_HTML;
|
||||
public static final String FORMATS_HTML_JSON = "html/json";
|
||||
public static final String FORMATS_HTML_XML = "html/xml";
|
||||
public static final String HEADER_ACCEPT = "Accept";
|
||||
public static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";
|
||||
public static final String HEADER_ACCEPT_VALUE_XML_OR_JSON = CT_FHIR_XML + ";q=1.0, " + CT_FHIR_JSON + ";q=1.0";
|
||||
|
@ -103,6 +105,7 @@ public class Constants {
|
|||
public static final String LINK_PREVIOUS = "previous";
|
||||
public static final String LINK_SELF = "self";
|
||||
public static final String OPENSEARCH_NS_OLDER = "http://purl.org/atompub/tombstones/1.0";
|
||||
public static final String PARAM_AT = "_at";
|
||||
/**
|
||||
* Used in paging links
|
||||
*/
|
||||
|
@ -155,15 +158,13 @@ public class Constants {
|
|||
public static final int STATUS_HTTP_410_GONE = 410;
|
||||
public static final int STATUS_HTTP_412_PRECONDITION_FAILED = 412;
|
||||
public static final int STATUS_HTTP_422_UNPROCESSABLE_ENTITY = 422;
|
||||
|
||||
public static final int STATUS_HTTP_500_INTERNAL_ERROR = 500;
|
||||
public static final int STATUS_HTTP_501_NOT_IMPLEMENTED = 501;
|
||||
public static final String TAG_SUBSETTED_CODE = "SUBSETTED";
|
||||
|
||||
public static final String TAG_SUBSETTED_SYSTEM = "http://hl7.org/fhir/v3/ObservationValue";
|
||||
public static final String URL_TOKEN_HISTORY = "_history";
|
||||
public static final String URL_TOKEN_METADATA = "metadata";
|
||||
public static final String FORMATS_HTML_JSON = "html/json";
|
||||
public static final String FORMATS_HTML_XML = "html/xml";
|
||||
|
||||
static {
|
||||
Map<String, EncodingEnum> valToEncoding = new HashMap<String, EncodingEnum>();
|
||||
|
|
|
@ -30,6 +30,7 @@ import java.util.LinkedHashSet;
|
|||
import java.util.List;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import javassist.Modifier;
|
||||
|
||||
public class ReflectionUtil {
|
||||
|
||||
|
@ -153,4 +154,8 @@ public class ReflectionUtil {
|
|||
}
|
||||
}
|
||||
|
||||
public static boolean isInstantiable(Class<?> theType) {
|
||||
return !theType.isInterface() && !Modifier.isAbstract(theType.getModifiers());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ public class AbstractJaxRsConformanceProviderTest {
|
|||
Response response = createConformanceProvider(providers).conformance();
|
||||
assertEquals(Constants.STATUS_HTTP_200_OK, response.getStatus());
|
||||
assertTrue(response.getEntity().toString().contains("\"type\":\"Patient\""));
|
||||
assertTrue(response.getEntity().toString().contains("\"$someCustomOperation"));
|
||||
assertTrue(response.getEntity().toString().contains("\"someCustomOperation"));
|
||||
System.out.println(response);
|
||||
System.out.println(response.getEntity());
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ public class AbstractJaxRsConformanceProviderTest {
|
|||
assertEquals(Constants.STATUS_HTTP_200_OK, response.getStatus());
|
||||
System.out.println(response.getEntity());
|
||||
assertTrue(response.getEntity().toString().contains(" <type value=\"Patient\"/>"));
|
||||
assertTrue(response.getEntity().toString().contains("\"$someCustomOperation"));
|
||||
assertTrue(response.getEntity().toString().contains("\"someCustomOperation"));
|
||||
System.out.println(response.getEntity());
|
||||
}
|
||||
|
||||
|
|
|
@ -474,19 +474,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
}
|
||||
}
|
||||
|
||||
private List<Object> extractValues(String thePath, IBaseResource theResource) {
|
||||
List<Object> values = new ArrayList<Object>();
|
||||
FhirTerser t = getContext().newTerser();
|
||||
String nextPathTrimmed = thePath.trim();
|
||||
try {
|
||||
values.addAll(t.getValues(theResource, nextPathTrimmed));
|
||||
} catch (Exception e) {
|
||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
|
||||
ourLog.warn("Failed to index values from path[{}] in resource type[{}]: ", new Object[] { nextPathTrimmed, def.getName(), e.toString() });
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
private void findMatchingTagIds(String theResourceName, IIdType theResourceId, Set<Long> tagIds, Class<? extends BaseTag> entityClass) {
|
||||
{
|
||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
||||
|
@ -621,13 +608,13 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
}
|
||||
}
|
||||
|
||||
protected IBundleProvider history(String theResourceName, Long theId, Date theSince) {
|
||||
protected IBundleProvider history(String theResourceName, Long theId, Date theSince, Date theUntil) {
|
||||
|
||||
String resourceName = defaultIfBlank(theResourceName, null);
|
||||
|
||||
Search search = new Search();
|
||||
search.setCreated(new Date());
|
||||
search.setLastUpdated(null, theSince);
|
||||
search.setLastUpdated(theSince, theUntil);
|
||||
search.setUuid(UUID.randomUUID().toString());
|
||||
search.setResourceType(resourceName);
|
||||
search.setResourceId(theId);
|
||||
|
@ -661,7 +648,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
theProvider.setContext(getContext());
|
||||
theProvider.setEntityManager(myEntityManager);
|
||||
theProvider.setPlatformTransactionManager(myPlatformTransactionManager);
|
||||
theProvider.setResourceHistoryTableDao(myResourceHistoryTableDao);
|
||||
theProvider.setSearchDao(mySearchDao);
|
||||
theProvider.setSearchResultDao(mySearchResultDao);
|
||||
}
|
||||
|
|
|
@ -101,20 +101,23 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
@Autowired
|
||||
protected PlatformTransactionManager myPlatformTransactionManager;
|
||||
|
||||
private String myResourceName;
|
||||
@Autowired
|
||||
private IResourceHistoryTableDao myResourceHistoryTableDao;
|
||||
|
||||
@Autowired()
|
||||
protected IResourceIndexedSearchParamUriDao myResourceIndexedSearchParamUriDao;
|
||||
private String myResourceName;
|
||||
private Class<T> myResourceType;
|
||||
@Autowired(required = false)
|
||||
protected IFulltextSearchSvc mySearchDao;
|
||||
@Autowired()
|
||||
protected ISearchResultDao mySearchResultDao;
|
||||
@Autowired()
|
||||
protected IResourceIndexedSearchParamUriDao myResourceIndexedSearchParamUriDao;
|
||||
@Autowired()
|
||||
protected IHapiTerminologySvc myTerminologySvc;
|
||||
|
||||
private String mySecondaryPrimaryKeyParamName;
|
||||
|
||||
@Autowired()
|
||||
protected IHapiTerminologySvc myTerminologySvc;
|
||||
|
||||
@Override
|
||||
public void addTag(IIdType theId, TagTypeEnum theTagType, String theScheme, String theTerm, String theLabel) {
|
||||
StopWatch w = new StopWatch();
|
||||
|
@ -149,11 +152,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
return create(theResource, null, true, theRequestDetails);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DaoMethodOutcome create(final T theResource, String theIfNoneExist, RequestDetails theRequestDetails) {
|
||||
return create(theResource, theIfNoneExist, true, theRequestDetails);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DaoMethodOutcome create(T theResource, String theIfNoneExist, boolean thePerformIndexing, RequestDetails theRequestDetails) {
|
||||
if (isNotBlank(theResource.getIdElement().getIdPart())) {
|
||||
|
@ -171,6 +169,11 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
return doCreate(theResource, theIfNoneExist, thePerformIndexing, new Date(), theRequestDetails);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DaoMethodOutcome create(final T theResource, String theIfNoneExist, RequestDetails theRequestDetails) {
|
||||
return create(theResource, theIfNoneExist, true, theRequestDetails);
|
||||
}
|
||||
|
||||
public IBaseOperationOutcome createErrorOperationOutcome(String theMessage, String theCode) {
|
||||
return createOperationOutcome(OO_SEVERITY_ERROR, theMessage, theCode);
|
||||
}
|
||||
|
@ -181,19 +184,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
|
||||
protected abstract IBaseOperationOutcome createOperationOutcome(String theSeverity, String theMessage, String theCode);
|
||||
|
||||
@Override
|
||||
public DaoMethodOutcome delete(IIdType theId, RequestDetails theRequestDetails) {
|
||||
List<DeleteConflict> deleteConflicts = new ArrayList<DeleteConflict>();
|
||||
StopWatch w = new StopWatch();
|
||||
|
||||
ResourceTable savedEntity = delete(theId, deleteConflicts, theRequestDetails);
|
||||
|
||||
validateDeleteConflictsEmptyOrThrowException(deleteConflicts);
|
||||
|
||||
ourLog.info("Processed delete on {} in {}ms", theId.getValue(), w.getMillisAndRestart());
|
||||
return toMethodOutcome(savedEntity, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceTable delete(IIdType theId, List<DeleteConflict> deleteConflicts, RequestDetails theRequestDetails) {
|
||||
if (theId == null || !theId.hasIdPart()) {
|
||||
|
@ -225,20 +215,16 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
}
|
||||
|
||||
@Override
|
||||
public DaoMethodOutcome deleteByUrl(String theUrl, RequestDetails theRequestDetails) {
|
||||
StopWatch w = new StopWatch();
|
||||
public DaoMethodOutcome delete(IIdType theId, RequestDetails theRequestDetails) {
|
||||
List<DeleteConflict> deleteConflicts = new ArrayList<DeleteConflict>();
|
||||
StopWatch w = new StopWatch();
|
||||
|
||||
List<ResourceTable> deletedResources = deleteByUrl(theUrl, deleteConflicts, theRequestDetails);
|
||||
ResourceTable savedEntity = delete(theId, deleteConflicts, theRequestDetails);
|
||||
|
||||
validateDeleteConflictsEmptyOrThrowException(deleteConflicts);
|
||||
|
||||
if (deletedResources.isEmpty()) {
|
||||
throw new ResourceNotFoundException(getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "unableToDeleteNotFound", theUrl));
|
||||
}
|
||||
|
||||
ourLog.info("Processed delete on {} (matched {} resource(s)) in {}ms", new Object[] { theUrl, deletedResources.size(), w.getMillisAndRestart() });
|
||||
return new DaoMethodOutcome();
|
||||
ourLog.info("Processed delete on {} in {}ms", theId.getValue(), w.getMillisAndRestart());
|
||||
return toMethodOutcome(savedEntity, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -280,6 +266,23 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DaoMethodOutcome deleteByUrl(String theUrl, RequestDetails theRequestDetails) {
|
||||
StopWatch w = new StopWatch();
|
||||
List<DeleteConflict> deleteConflicts = new ArrayList<DeleteConflict>();
|
||||
|
||||
List<ResourceTable> deletedResources = deleteByUrl(theUrl, deleteConflicts, theRequestDetails);
|
||||
|
||||
validateDeleteConflictsEmptyOrThrowException(deleteConflicts);
|
||||
|
||||
if (deletedResources.isEmpty()) {
|
||||
throw new ResourceNotFoundException(getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "unableToDeleteNotFound", theUrl));
|
||||
}
|
||||
|
||||
ourLog.info("Processed delete on {} (matched {} resource(s)) in {}ms", new Object[] { theUrl, deletedResources.size(), w.getMillisAndRestart() });
|
||||
return new DaoMethodOutcome();
|
||||
}
|
||||
|
||||
private DaoMethodOutcome doCreate(T theResource, String theIfNoneExist, boolean thePerformIndexing, Date theUpdateTime, RequestDetails theRequestDetails) {
|
||||
StopWatch w = new StopWatch();
|
||||
|
||||
|
@ -302,7 +305,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
|
||||
if (isNotBlank(theResource.getIdElement().getIdPart())) {
|
||||
if (isValidPid(theResource.getIdElement())) {
|
||||
throw new UnprocessableEntityException("This server cannot create an entity with a user-specified numeric ID - Client should not specify an ID when creating a new resource, or should include at least one letter in the ID to force a client-defined ID");
|
||||
throw new UnprocessableEntityException(
|
||||
"This server cannot create an entity with a user-specified numeric ID - Client should not specify an ID when creating a new resource, or should include at least one letter in the ID to force a client-defined ID");
|
||||
}
|
||||
createForcedIdIfNeeded(entity, theResource.getIdElement());
|
||||
|
||||
|
@ -342,6 +346,58 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
return outcome;
|
||||
}
|
||||
|
||||
private <MT extends IBaseMetaType> void doMetaAdd(MT theMetaAdd, BaseHasResource entity) {
|
||||
List<TagDefinition> tags = toTagList(theMetaAdd);
|
||||
|
||||
//@formatter:off
|
||||
for (TagDefinition nextDef : tags) {
|
||||
|
||||
boolean hasTag = false;
|
||||
for (BaseTag next : new ArrayList<BaseTag>(entity.getTags())) {
|
||||
if (ObjectUtil.equals(next.getTag().getTagType(), nextDef.getTagType()) &&
|
||||
ObjectUtil.equals(next.getTag().getSystem(), nextDef.getSystem()) &&
|
||||
ObjectUtil.equals(next.getTag().getCode(), nextDef.getCode())) {
|
||||
hasTag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasTag) {
|
||||
entity.setHasTags(true);
|
||||
|
||||
TagDefinition def = getTag(nextDef.getTagType(), nextDef.getSystem(), nextDef.getCode(), nextDef.getDisplay());
|
||||
BaseTag newEntity = entity.addTag(def);
|
||||
myEntityManager.persist(newEntity);
|
||||
}
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
myEntityManager.merge(entity);
|
||||
}
|
||||
|
||||
private <MT extends IBaseMetaType> void doMetaDelete(MT theMetaDel, BaseHasResource entity) {
|
||||
List<TagDefinition> tags = toTagList(theMetaDel);
|
||||
|
||||
//@formatter:off
|
||||
for (TagDefinition nextDef : tags) {
|
||||
for (BaseTag next : new ArrayList<BaseTag>(entity.getTags())) {
|
||||
if (ObjectUtil.equals(next.getTag().getTagType(), nextDef.getTagType()) &&
|
||||
ObjectUtil.equals(next.getTag().getSystem(), nextDef.getSystem()) &&
|
||||
ObjectUtil.equals(next.getTag().getCode(), nextDef.getCode())) {
|
||||
myEntityManager.remove(next);
|
||||
entity.getTags().remove(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
if (entity.getTags().isEmpty()) {
|
||||
entity.setHasTags(false);
|
||||
}
|
||||
|
||||
myEntityManager.merge(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagList getAllResourceTags(RequestDetails theRequestDetails) {
|
||||
// Notify interceptors
|
||||
|
@ -378,19 +434,19 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
}
|
||||
|
||||
@Override
|
||||
public IBundleProvider history(Date theSince, RequestDetails theRequestDetails) {
|
||||
public IBundleProvider history(Date theSince, Date theUntil, RequestDetails theRequestDetails) {
|
||||
// Notify interceptors
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(null, null, getContext(), theRequestDetails);
|
||||
notifyInterceptors(RestOperationTypeEnum.HISTORY_SYSTEM, requestDetails);
|
||||
notifyInterceptors(RestOperationTypeEnum.HISTORY_TYPE, requestDetails);
|
||||
|
||||
StopWatch w = new StopWatch();
|
||||
IBundleProvider retVal = super.history(myResourceName, null, theSince);
|
||||
IBundleProvider retVal = super.history(myResourceName, null, theSince, theUntil);
|
||||
ourLog.info("Processed history on {} in {}ms", myResourceName, w.getMillisAndRestart());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBundleProvider history(final IIdType theId, final Date theSince, RequestDetails theRequestDetails) {
|
||||
public IBundleProvider history(final IIdType theId, final Date theSince, Date theUntil, RequestDetails theRequestDetails) {
|
||||
// Notify interceptors
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theId, getResourceName(), getContext(), theRequestDetails);
|
||||
notifyInterceptors(RestOperationTypeEnum.HISTORY_INSTANCE, requestDetails);
|
||||
|
@ -400,86 +456,12 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
IIdType id = theId.withResourceType(myResourceName).toUnqualifiedVersionless();
|
||||
BaseHasResource entity = readEntity(id);
|
||||
|
||||
IBundleProvider retVal = super.history(myResourceName, entity.getId(), theSince);
|
||||
IBundleProvider retVal = super.history(myResourceName, entity.getId(), theSince, theUntil);
|
||||
|
||||
ourLog.info("Processed history on {} in {}ms", id, w.getMillisAndRestart());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBundleProvider history(Long theId, Date theSince, RequestDetails theRequestDetails) {
|
||||
// Notify interceptors
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName(), getContext(), theRequestDetails);
|
||||
notifyInterceptors(RestOperationTypeEnum.HISTORY_TYPE, requestDetails);
|
||||
|
||||
StopWatch w = new StopWatch();
|
||||
IBundleProvider retVal = super.history(myResourceName, theId, theSince);
|
||||
ourLog.info("Processed history on {} in {}ms", theId, w.getMillisAndRestart());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private IResourceHistoryTableDao myResourceHistoryTableDao;
|
||||
|
||||
@Override
|
||||
public <MT extends IBaseMetaType> MT metaAddOperation(IIdType theResourceId, MT theMetaAdd, RequestDetails theRequestDetails) {
|
||||
// Notify interceptors
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theResourceId, getResourceName(), getContext(), theRequestDetails);
|
||||
notifyInterceptors(RestOperationTypeEnum.META_ADD, requestDetails);
|
||||
|
||||
StopWatch w = new StopWatch();
|
||||
BaseHasResource entity = readEntity(theResourceId);
|
||||
if (entity == null) {
|
||||
throw new ResourceNotFoundException(theResourceId);
|
||||
}
|
||||
|
||||
ResourceTable latestVersion = readEntityLatestVersion(theResourceId);
|
||||
if (latestVersion.getVersion() != entity.getVersion()) {
|
||||
doMetaAdd(theMetaAdd, entity);
|
||||
} else {
|
||||
doMetaAdd(theMetaAdd, latestVersion);
|
||||
|
||||
// Also update history entry
|
||||
ResourceHistoryTable history = myResourceHistoryTableDao.findForIdAndVersion(entity.getId(), entity.getVersion());
|
||||
doMetaAdd(theMetaAdd, history);
|
||||
}
|
||||
|
||||
ourLog.info("Processed metaAddOperation on {} in {}ms", new Object[] { theResourceId, w.getMillisAndRestart() });
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
MT retVal = (MT) metaGetOperation(theMetaAdd.getClass(), theResourceId, theRequestDetails);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private <MT extends IBaseMetaType> void doMetaAdd(MT theMetaAdd, BaseHasResource entity) {
|
||||
List<TagDefinition> tags = toTagList(theMetaAdd);
|
||||
|
||||
//@formatter:off
|
||||
for (TagDefinition nextDef : tags) {
|
||||
|
||||
boolean hasTag = false;
|
||||
for (BaseTag next : new ArrayList<BaseTag>(entity.getTags())) {
|
||||
if (ObjectUtil.equals(next.getTag().getTagType(), nextDef.getTagType()) &&
|
||||
ObjectUtil.equals(next.getTag().getSystem(), nextDef.getSystem()) &&
|
||||
ObjectUtil.equals(next.getTag().getCode(), nextDef.getCode())) {
|
||||
hasTag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasTag) {
|
||||
entity.setHasTags(true);
|
||||
|
||||
TagDefinition def = getTag(nextDef.getTagType(), nextDef.getSystem(), nextDef.getCode(), nextDef.getDisplay());
|
||||
BaseTag newEntity = entity.addTag(def);
|
||||
myEntityManager.persist(newEntity);
|
||||
}
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
myEntityManager.merge(entity);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public IBundleProvider everything(IIdType theId) {
|
||||
// Search search = new Search();
|
||||
|
@ -562,6 +544,36 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
// };
|
||||
// }
|
||||
|
||||
@Override
|
||||
public <MT extends IBaseMetaType> MT metaAddOperation(IIdType theResourceId, MT theMetaAdd, RequestDetails theRequestDetails) {
|
||||
// Notify interceptors
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theResourceId, getResourceName(), getContext(), theRequestDetails);
|
||||
notifyInterceptors(RestOperationTypeEnum.META_ADD, requestDetails);
|
||||
|
||||
StopWatch w = new StopWatch();
|
||||
BaseHasResource entity = readEntity(theResourceId);
|
||||
if (entity == null) {
|
||||
throw new ResourceNotFoundException(theResourceId);
|
||||
}
|
||||
|
||||
ResourceTable latestVersion = readEntityLatestVersion(theResourceId);
|
||||
if (latestVersion.getVersion() != entity.getVersion()) {
|
||||
doMetaAdd(theMetaAdd, entity);
|
||||
} else {
|
||||
doMetaAdd(theMetaAdd, latestVersion);
|
||||
|
||||
// Also update history entry
|
||||
ResourceHistoryTable history = myResourceHistoryTableDao.findForIdAndVersion(entity.getId(), entity.getVersion());
|
||||
doMetaAdd(theMetaAdd, history);
|
||||
}
|
||||
|
||||
ourLog.info("Processed metaAddOperation on {} in {}ms", new Object[] { theResourceId, w.getMillisAndRestart() });
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
MT retVal = (MT) metaGetOperation(theMetaAdd.getClass(), theResourceId, theRequestDetails);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <MT extends IBaseMetaType> MT metaDeleteOperation(IIdType theResourceId, MT theMetaDel, RequestDetails theRequestDetails) {
|
||||
// Notify interceptors
|
||||
|
@ -594,68 +606,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
return retVal;
|
||||
}
|
||||
|
||||
private <MT extends IBaseMetaType> void doMetaDelete(MT theMetaDel, BaseHasResource entity) {
|
||||
List<TagDefinition> tags = toTagList(theMetaDel);
|
||||
|
||||
//@formatter:off
|
||||
for (TagDefinition nextDef : tags) {
|
||||
for (BaseTag next : new ArrayList<BaseTag>(entity.getTags())) {
|
||||
if (ObjectUtil.equals(next.getTag().getTagType(), nextDef.getTagType()) &&
|
||||
ObjectUtil.equals(next.getTag().getSystem(), nextDef.getSystem()) &&
|
||||
ObjectUtil.equals(next.getTag().getCode(), nextDef.getCode())) {
|
||||
myEntityManager.remove(next);
|
||||
entity.getTags().remove(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
if (entity.getTags().isEmpty()) {
|
||||
entity.setHasTags(false);
|
||||
}
|
||||
|
||||
myEntityManager.merge(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <MT extends IBaseMetaType> MT metaGetOperation(Class<MT> theType, RequestDetails theRequestDetails) {
|
||||
// Notify interceptors
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName(), getContext(), theRequestDetails);
|
||||
notifyInterceptors(RestOperationTypeEnum.META, requestDetails);
|
||||
|
||||
String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t WHERE t.myResourceType = :res_type)";
|
||||
TypedQuery<TagDefinition> q = myEntityManager.createQuery(sql, TagDefinition.class);
|
||||
q.setParameter("res_type", myResourceName);
|
||||
List<TagDefinition> tagDefinitions = q.getResultList();
|
||||
|
||||
MT retVal = toMetaDt(theType, tagDefinitions);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
protected <MT extends IBaseMetaType> MT toMetaDt(Class<MT> theType, Collection<TagDefinition> tagDefinitions) {
|
||||
MT retVal;
|
||||
try {
|
||||
retVal = theType.newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new InternalErrorException("Failed to instantiate " + theType.getName(), e);
|
||||
}
|
||||
for (TagDefinition next : tagDefinitions) {
|
||||
switch (next.getTagType()) {
|
||||
case PROFILE:
|
||||
retVal.addProfile(next.getCode());
|
||||
break;
|
||||
case SECURITY_LABEL:
|
||||
retVal.addSecurity().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
|
||||
break;
|
||||
case TAG:
|
||||
retVal.addTag().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
|
||||
break;
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <MT extends IBaseMetaType> MT metaGetOperation(Class<MT> theType, IIdType theId, RequestDetails theRequestDetails) {
|
||||
// Notify interceptors
|
||||
|
@ -675,6 +625,22 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <MT extends IBaseMetaType> MT metaGetOperation(Class<MT> theType, RequestDetails theRequestDetails) {
|
||||
// Notify interceptors
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName(), getContext(), theRequestDetails);
|
||||
notifyInterceptors(RestOperationTypeEnum.META, requestDetails);
|
||||
|
||||
String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t WHERE t.myResourceType = :res_type)";
|
||||
TypedQuery<TagDefinition> q = myEntityManager.createQuery(sql, TagDefinition.class);
|
||||
q.setParameter("res_type", myResourceName);
|
||||
List<TagDefinition> tagDefinitions = q.getResultList();
|
||||
|
||||
MT retVal = toMetaDt(theType, tagDefinitions);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(myResourceType);
|
||||
|
@ -711,8 +677,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
}
|
||||
|
||||
/*
|
||||
* Replace absolute references with relative ones if configured to
|
||||
* do so
|
||||
* Replace absolute references with relative ones if configured to do so
|
||||
*/
|
||||
if (getConfig().getTreatBaseUrlsAsLocal().isEmpty() == false) {
|
||||
FhirTerser t = getContext().newTerser();
|
||||
|
@ -772,7 +737,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
return entity;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BaseHasResource readEntity(IIdType theId, boolean theCheckForForcedId) {
|
||||
validateResourceTypeAndThrowIllegalArgumentException(theId);
|
||||
|
@ -795,7 +759,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
|
||||
if (entity == null) {
|
||||
if (theId.hasVersionIdPart()) {
|
||||
TypedQuery<ResourceHistoryTable> q = myEntityManager.createQuery("SELECT t from ResourceHistoryTable t WHERE t.myResourceId = :RID AND t.myResourceType = :RTYP AND t.myResourceVersion = :RVER", ResourceHistoryTable.class);
|
||||
TypedQuery<ResourceHistoryTable> q = myEntityManager
|
||||
.createQuery("SELECT t from ResourceHistoryTable t WHERE t.myResourceId = :RID AND t.myResourceType = :RTYP AND t.myResourceVersion = :RVER", ResourceHistoryTable.class);
|
||||
q.setParameter("RID", pid);
|
||||
q.setParameter("RTYP", myResourceName);
|
||||
q.setParameter("RVER", theId.getVersionIdPartAsLong());
|
||||
|
@ -876,7 +841,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName(), getContext(), theParams.getRequestDetails());
|
||||
notifyInterceptors(RestOperationTypeEnum.SEARCH_TYPE, requestDetails);
|
||||
|
||||
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this, myResourceIndexedSearchParamUriDao, myForcedIdDao, myTerminologySvc);
|
||||
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this, myResourceIndexedSearchParamUriDao, myForcedIdDao,
|
||||
myTerminologySvc);
|
||||
builder.setType(getResourceType(), getResourceName());
|
||||
return builder.search(theParams);
|
||||
}
|
||||
|
@ -904,7 +870,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
public Set<Long> searchForIdsWithAndOr(SearchParameterMap theParams) {
|
||||
theParams.setPersistResults(false);
|
||||
|
||||
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this, myResourceIndexedSearchParamUriDao, myForcedIdDao, myTerminologySvc);
|
||||
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this, myResourceIndexedSearchParamUriDao, myForcedIdDao,
|
||||
myTerminologySvc);
|
||||
builder.setType(getResourceType(), getResourceName());
|
||||
builder.search(theParams);
|
||||
return builder.doGetPids();
|
||||
|
@ -917,13 +884,35 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
}
|
||||
|
||||
/**
|
||||
* If set, the given param will be treated as a secondary primary key, and multiple resources will not be able to
|
||||
* share the same value.
|
||||
* If set, the given param will be treated as a secondary primary key, and multiple resources will not be able to share the same value.
|
||||
*/
|
||||
public void setSecondaryPrimaryKeyParamName(String theSecondaryPrimaryKeyParamName) {
|
||||
mySecondaryPrimaryKeyParamName = theSecondaryPrimaryKeyParamName;
|
||||
}
|
||||
|
||||
protected <MT extends IBaseMetaType> MT toMetaDt(Class<MT> theType, Collection<TagDefinition> tagDefinitions) {
|
||||
MT retVal;
|
||||
try {
|
||||
retVal = theType.newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new InternalErrorException("Failed to instantiate " + theType.getName(), e);
|
||||
}
|
||||
for (TagDefinition next : tagDefinitions) {
|
||||
switch (next.getTagType()) {
|
||||
case PROFILE:
|
||||
retVal.addProfile(next.getCode());
|
||||
break;
|
||||
case SECURITY_LABEL:
|
||||
retVal.addSecurity().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
|
||||
break;
|
||||
case TAG:
|
||||
retVal.addTag().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
|
||||
break;
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private DaoMethodOutcome toMethodOutcome(final BaseHasResource theEntity, IBaseResource theResource) {
|
||||
DaoMethodOutcome outcome = new DaoMethodOutcome();
|
||||
|
||||
|
@ -973,18 +962,12 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
return update(theResource, null, theRequestDetails);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DaoMethodOutcome update(T theResource, String theMatchUrl, RequestDetails theRequestDetails) {
|
||||
return update(theResource, theMatchUrl, true, theRequestDetails);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DaoMethodOutcome update(T theResource, String theMatchUrl, boolean thePerformIndexing, RequestDetails theRequestDetails) {
|
||||
StopWatch w = new StopWatch();
|
||||
|
||||
preProcessResourceForStorage(theResource);
|
||||
|
||||
|
||||
final ResourceTable entity;
|
||||
|
||||
IIdType resourceId;
|
||||
|
@ -1001,8 +984,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
return create(theResource, null, thePerformIndexing, theRequestDetails);
|
||||
}
|
||||
} else {
|
||||
/* Note: resourcdeId will not be null or empty here, because
|
||||
* we check it and reject requests in BaseOutcomeReturningMethodBindingWithResourceParam
|
||||
/*
|
||||
* Note: resourcdeId will not be null or empty here, because we check it and reject requests in BaseOutcomeReturningMethodBindingWithResourceParam
|
||||
*/
|
||||
resourceId = theResource.getIdElement();
|
||||
|
||||
|
@ -1010,7 +993,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
entity = readEntityLatestVersion(resourceId);
|
||||
} catch (ResourceNotFoundException e) {
|
||||
if (resourceId.isIdPartValidLong()) {
|
||||
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "failedToCreateWithClientAssignedNumericId", theResource.getIdElement().getIdPart()));
|
||||
throw new InvalidRequestException(
|
||||
getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "failedToCreateWithClientAssignedNumericId", theResource.getIdElement().getIdPart()));
|
||||
}
|
||||
return doCreate(theResource, null, thePerformIndexing, new Date(), theRequestDetails);
|
||||
}
|
||||
|
@ -1021,7 +1005,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
}
|
||||
|
||||
if (resourceId.hasResourceType() && !resourceId.getResourceType().equals(getResourceName())) {
|
||||
throw new UnprocessableEntityException("Invalid resource ID[" + entity.getIdDt().toUnqualifiedVersionless() + "] of type[" + entity.getResourceType() + "] - Does not match expected [" + getResourceName() + "]");
|
||||
throw new UnprocessableEntityException(
|
||||
"Invalid resource ID[" + entity.getIdDt().toUnqualifiedVersionless() + "] of type[" + entity.getResourceType() + "] - Does not match expected [" + getResourceName() + "]");
|
||||
}
|
||||
|
||||
// Notify interceptors
|
||||
|
@ -1048,6 +1033,11 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
return outcome;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DaoMethodOutcome update(T theResource, String theMatchUrl, RequestDetails theRequestDetails) {
|
||||
return update(theResource, theMatchUrl, true, theRequestDetails);
|
||||
}
|
||||
|
||||
private void validateGivenIdIsAppropriateToRetrieveResource(IIdType theId, BaseHasResource entity) {
|
||||
if (entity.getForcedId() != null) {
|
||||
if (theId.isIdPartValidLong()) {
|
||||
|
|
|
@ -219,13 +219,13 @@ public abstract class BaseHapiFhirSystemDao<T, MT> extends BaseHapiFhirDao<IBase
|
|||
}
|
||||
|
||||
@Override
|
||||
public IBundleProvider history(Date theSince, RequestDetails theRequestDetails) {
|
||||
public IBundleProvider history(Date theSince, Date theUntil, RequestDetails theRequestDetails) {
|
||||
// Notify interceptors
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(null, null, getContext(), theRequestDetails);
|
||||
notifyInterceptors(RestOperationTypeEnum.HISTORY_SYSTEM, requestDetails);
|
||||
|
||||
StopWatch w = new StopWatch();
|
||||
IBundleProvider retVal = super.history(null, null, theSince);
|
||||
IBundleProvider retVal = super.history(null, null, theSince, theUntil);
|
||||
ourLog.info("Processed global history in {}ms", w.getMillisAndRestart());
|
||||
return retVal;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@ import ca.uhn.fhir.model.api.TagList;
|
|||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.ValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
|
@ -92,11 +91,9 @@ public interface IFhirResourceDao<T extends IBaseResource> extends IDao {
|
|||
|
||||
TagList getTags(IIdType theResourceId, RequestDetails theRequestDetails);
|
||||
|
||||
IBundleProvider history(Date theSince, RequestDetails theRequestDetails);
|
||||
IBundleProvider history(Date theSince, Date theUntil, RequestDetails theRequestDetails);
|
||||
|
||||
IBundleProvider history(IIdType theId, Date theSince, RequestDetails theRequestDetails);
|
||||
|
||||
IBundleProvider history(Long theId, Date theSince, RequestDetails theRequestDetails);
|
||||
IBundleProvider history(IIdType theId, Date theSince, Date theUntil, RequestDetails theRequestDetails);
|
||||
|
||||
/**
|
||||
* Not supported in DSTU1!
|
||||
|
|
|
@ -47,7 +47,7 @@ public interface IFhirSystemDao<T, MT> extends IDao {
|
|||
|
||||
Map<String, Long> getResourceCounts();
|
||||
|
||||
IBundleProvider history(Date theDate, RequestDetails theRequestDetails);
|
||||
IBundleProvider history(Date theDate, Date theUntil, RequestDetails theRequestDetails);
|
||||
|
||||
/**
|
||||
* Marks all indexes as needing fresh indexing
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
package ca.uhn.fhir.jpa.dao.data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
|
@ -68,36 +65,36 @@ public interface IResourceHistoryTableDao extends JpaRepository<ResourceHistoryT
|
|||
@Param("type") String theType
|
||||
);
|
||||
|
||||
@Query("SELECT t FROM ResourceHistoryTable t WHERE t.myUpdated >= :cutoff ORDER BY t.myUpdated DESC")
|
||||
List<ResourceHistoryTable> findForAllResourceTypes(
|
||||
@Temporal(value=TemporalType.TIMESTAMP) @Param("cutoff") Date theCutoff,
|
||||
Pageable thePageable);
|
||||
|
||||
@Query("SELECT t FROM ResourceHistoryTable t WHERE t.myResourceId = :id AND t.myUpdated >= :cutoff ORDER BY t.myUpdated DESC")
|
||||
List<ResourceHistoryTable> findForResourceInstance(
|
||||
@Param("id") Long theId,
|
||||
@Temporal(value=TemporalType.TIMESTAMP) @Param("cutoff") Date theCutoff,
|
||||
Pageable thePageable);
|
||||
|
||||
@Query("SELECT t FROM ResourceHistoryTable t WHERE t.myResourceType = :type AND t.myUpdated >= :cutoff ORDER BY t.myUpdated DESC")
|
||||
List<ResourceHistoryTable> findForResourceType(
|
||||
@Param("type") String theType,
|
||||
@Temporal(value=TemporalType.TIMESTAMP) @Param("cutoff") Date theCutoff,
|
||||
Pageable thePageable);
|
||||
|
||||
@Query("SELECT t FROM ResourceHistoryTable t ORDER BY t.myUpdated DESC")
|
||||
List<ResourceHistoryTable> findForAllResourceTypes(
|
||||
Pageable thePageable);
|
||||
|
||||
@Query("SELECT t FROM ResourceHistoryTable t WHERE t.myResourceId = :id ORDER BY t.myUpdated DESC")
|
||||
List<ResourceHistoryTable> findForResourceInstance(
|
||||
@Param("id") Long theId,
|
||||
Pageable thePageable);
|
||||
|
||||
@Query("SELECT t FROM ResourceHistoryTable t WHERE t.myResourceType = :type ORDER BY t.myUpdated DESC")
|
||||
List<ResourceHistoryTable> findForResourceType(
|
||||
@Param("type") String theType,
|
||||
Pageable thePageable);
|
||||
// @Query("SELECT t FROM ResourceHistoryTable t WHERE t.myUpdated >= :cutoff ORDER BY t.myUpdated DESC")
|
||||
// List<ResourceHistoryTable> findForAllResourceTypes(
|
||||
// @Temporal(value=TemporalType.TIMESTAMP) @Param("cutoff") Date theCutoff,
|
||||
// Pageable thePageable);
|
||||
//
|
||||
// @Query("SELECT t FROM ResourceHistoryTable t WHERE t.myResourceId = :id AND t.myUpdated >= :cutoff ORDER BY t.myUpdated DESC")
|
||||
// List<ResourceHistoryTable> findForResourceInstance(
|
||||
// @Param("id") Long theId,
|
||||
// @Temporal(value=TemporalType.TIMESTAMP) @Param("cutoff") Date theCutoff,
|
||||
// Pageable thePageable);
|
||||
//
|
||||
// @Query("SELECT t FROM ResourceHistoryTable t WHERE t.myResourceType = :type AND t.myUpdated >= :cutoff ORDER BY t.myUpdated DESC")
|
||||
// List<ResourceHistoryTable> findForResourceType(
|
||||
// @Param("type") String theType,
|
||||
// @Temporal(value=TemporalType.TIMESTAMP) @Param("cutoff") Date theCutoff,
|
||||
// Pageable thePageable);
|
||||
//
|
||||
// @Query("SELECT t FROM ResourceHistoryTable t ORDER BY t.myUpdated DESC")
|
||||
// List<ResourceHistoryTable> findForAllResourceTypes(
|
||||
// Pageable thePageable);
|
||||
//
|
||||
// @Query("SELECT t FROM ResourceHistoryTable t WHERE t.myResourceId = :id ORDER BY t.myUpdated DESC")
|
||||
// List<ResourceHistoryTable> findForResourceInstance(
|
||||
// @Param("id") Long theId,
|
||||
// Pageable thePageable);
|
||||
//
|
||||
// @Query("SELECT t FROM ResourceHistoryTable t WHERE t.myResourceType = :type ORDER BY t.myUpdated DESC")
|
||||
// List<ResourceHistoryTable> findForResourceType(
|
||||
// @Param("type") String theType,
|
||||
// Pageable thePageable);
|
||||
|
||||
@Query("SELECT t FROM ResourceHistoryTable t WHERE t.myResourceId = :id AND t.myResourceVersion = :version")
|
||||
ResourceHistoryTable findForIdAndVersion(@Param("id") long theId, @Param("version") long theVersion);
|
||||
|
|
|
@ -120,6 +120,10 @@ public class Search implements Serializable {
|
|||
return myLastUpdatedHigh;
|
||||
}
|
||||
|
||||
public Date getLastUpdatedLow() {
|
||||
return myLastUpdatedLow;
|
||||
}
|
||||
|
||||
public DateRangeParam getLastUpdated() {
|
||||
if (myLastUpdatedLow == null && myLastUpdatedHigh == null) {
|
||||
return null;
|
||||
|
|
|
@ -30,12 +30,14 @@ import org.springframework.beans.factory.annotation.Required;
|
|||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.model.api.TagList;
|
||||
import ca.uhn.fhir.rest.annotation.At;
|
||||
import ca.uhn.fhir.rest.annotation.GetTags;
|
||||
import ca.uhn.fhir.rest.annotation.History;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.Read;
|
||||
import ca.uhn.fhir.rest.annotation.Since;
|
||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
import ca.uhn.fhir.rest.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
|
@ -57,11 +59,20 @@ public abstract class BaseJpaResourceProvider<T extends IBaseResource> extends B
|
|||
return myDao;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@History
|
||||
public IBundleProvider getHistoryForResourceInstance(HttpServletRequest theRequest, @IdParam IIdType theId, @Since Date theDate, RequestDetails theRequestDetails) {
|
||||
public IBundleProvider getHistoryForResourceInstance(
|
||||
HttpServletRequest theRequest,
|
||||
@IdParam IIdType theId,
|
||||
@Since Date theSince,
|
||||
// @At DateRangeParam theAt,
|
||||
RequestDetails theRequestDetails) {
|
||||
//@formatter:on
|
||||
|
||||
startRequest(theRequest);
|
||||
try {
|
||||
return myDao.history(theId, theDate, theRequestDetails);
|
||||
// DateRangeParam sinceOrAt = processSinceOrAt(theSince)
|
||||
return myDao.history(theId, theSince, null, theRequestDetails);
|
||||
} finally {
|
||||
endRequest(theRequest);
|
||||
}
|
||||
|
@ -71,7 +82,7 @@ public abstract class BaseJpaResourceProvider<T extends IBaseResource> extends B
|
|||
public IBundleProvider getHistoryForResourceType(HttpServletRequest theRequest, @Since Date theDate, RequestDetails theRequestDetails) {
|
||||
startRequest(theRequest);
|
||||
try {
|
||||
return myDao.history(theDate, theRequestDetails);
|
||||
return myDao.history(theDate, null, theRequestDetails);
|
||||
} finally {
|
||||
endRequest(theRequest);
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ public class BaseJpaSystemProvider<T, MT> extends BaseJpaProvider {
|
|||
public IBundleProvider historyServer(HttpServletRequest theRequest, @Since Date theDate, RequestDetails theRequestDetails) {
|
||||
startRequest(theRequest);
|
||||
try {
|
||||
return myDao.history(theDate, theRequestDetails);
|
||||
return myDao.history(theDate, null, theRequestDetails);
|
||||
} finally {
|
||||
endRequest(theRequest);
|
||||
}
|
||||
|
|
|
@ -29,9 +29,13 @@ import java.util.Set;
|
|||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
@ -43,8 +47,6 @@ import org.springframework.transaction.support.TransactionTemplate;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.IDao;
|
||||
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
|
||||
import ca.uhn.fhir.jpa.entity.BaseHasResource;
|
||||
|
@ -61,7 +63,6 @@ public final class PersistedJpaBundleProvider implements IBundleProvider {
|
|||
private IDao myDao;
|
||||
private EntityManager myEntityManager;
|
||||
private PlatformTransactionManager myPlatformTransactionManager;
|
||||
private IResourceHistoryTableDao myResourceHistoryTableDao;
|
||||
private ISearchDao mySearchDao;
|
||||
private Search mySearchEntity;
|
||||
private ISearchResultDao mySearchResultDao;
|
||||
|
@ -72,35 +73,44 @@ public final class PersistedJpaBundleProvider implements IBundleProvider {
|
|||
myDao = theDao;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private IResourceTableDao myResourceTableDao;
|
||||
|
||||
protected List<IBaseResource> doHistoryInTransaction(int theFromIndex, int theToIndex) {
|
||||
|
||||
Date cutoff = mySearchEntity.getLastUpdatedHigh();
|
||||
|
||||
Pageable pageable = toPage(theFromIndex, theToIndex);
|
||||
|
||||
List<ResourceHistoryTable> results;
|
||||
|
||||
if (cutoff != null) {
|
||||
if (mySearchEntity.getResourceType() == null) {
|
||||
results = myResourceHistoryTableDao.findForAllResourceTypes(cutoff, pageable);
|
||||
} else if (mySearchEntity.getResourceId() == null) {
|
||||
results = myResourceHistoryTableDao.findForResourceType(mySearchEntity.getResourceType(), cutoff, pageable);
|
||||
} else {
|
||||
results = myResourceHistoryTableDao.findForResourceInstance(mySearchEntity.getResourceId(), cutoff, pageable);
|
||||
}
|
||||
CriteriaBuilder cb = myEntityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<ResourceHistoryTable> q = cb.createQuery(ResourceHistoryTable.class);
|
||||
Root<ResourceHistoryTable> from = q.from(ResourceHistoryTable.class);
|
||||
List<Predicate> predicates = new ArrayList<Predicate>();
|
||||
|
||||
if (mySearchEntity.getResourceType() == null) {
|
||||
// All resource types
|
||||
} else if (mySearchEntity.getResourceId() == null) {
|
||||
predicates.add(cb.equal(from.get("myResourceType"), mySearchEntity.getResourceType()));
|
||||
} else {
|
||||
if (mySearchEntity.getResourceType() == null) {
|
||||
results = myResourceHistoryTableDao.findForAllResourceTypes(pageable);
|
||||
} else if (mySearchEntity.getResourceId() == null) {
|
||||
results = myResourceHistoryTableDao.findForResourceType(mySearchEntity.getResourceType(), pageable);
|
||||
} else {
|
||||
results = myResourceHistoryTableDao.findForResourceInstance(mySearchEntity.getResourceId(), pageable);
|
||||
}
|
||||
predicates.add(cb.equal(from.get("myResourceId"), mySearchEntity.getResourceId()));
|
||||
}
|
||||
|
||||
if (mySearchEntity.getLastUpdatedLow() != null) {
|
||||
predicates.add(cb.greaterThanOrEqualTo(from.get("myUpdated").as(Date.class), mySearchEntity.getLastUpdatedLow()));
|
||||
}
|
||||
if (mySearchEntity.getLastUpdatedHigh() != null) {
|
||||
predicates.add(cb.lessThanOrEqualTo(from.get("myUpdated").as(Date.class), mySearchEntity.getLastUpdatedHigh()));
|
||||
}
|
||||
|
||||
if (predicates.size() > 0) {
|
||||
q.where(predicates.toArray(new Predicate[predicates.size()]));
|
||||
}
|
||||
|
||||
q.orderBy(cb.desc(from.get("myUpdated")));
|
||||
|
||||
TypedQuery<ResourceHistoryTable> query = myEntityManager.createQuery(q);
|
||||
|
||||
if (theToIndex - theFromIndex > 0) {
|
||||
query.setFirstResult(theFromIndex);
|
||||
query.setMaxResults(theToIndex - theFromIndex);
|
||||
}
|
||||
|
||||
results = query.getResultList();
|
||||
|
||||
ArrayList<IBaseResource> retVal = new ArrayList<IBaseResource>();
|
||||
for (ResourceHistoryTable next : results) {
|
||||
BaseHasResource resource;
|
||||
|
@ -176,7 +186,7 @@ public final class PersistedJpaBundleProvider implements IBundleProvider {
|
|||
|
||||
private void ensureDependenciesInjected() {
|
||||
if (myPlatformTransactionManager == null) {
|
||||
myDao.injectDependenciesIntoBundleProvider(this);
|
||||
myDao.injectDependenciesIntoBundleProvider(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,7 +217,6 @@ public final class PersistedJpaBundleProvider implements IBundleProvider {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -229,15 +238,10 @@ public final class PersistedJpaBundleProvider implements IBundleProvider {
|
|||
myEntityManager = theEntityManager;
|
||||
}
|
||||
|
||||
|
||||
public void setPlatformTransactionManager(PlatformTransactionManager thePlatformTransactionManager) {
|
||||
myPlatformTransactionManager = thePlatformTransactionManager;
|
||||
}
|
||||
|
||||
public void setResourceHistoryTableDao(IResourceHistoryTableDao theResourceHistoryTableDao) {
|
||||
myResourceHistoryTableDao = theResourceHistoryTableDao;
|
||||
}
|
||||
|
||||
public void setSearchDao(ISearchDao theSearchDao) {
|
||||
mySearchDao = theSearchDao;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ import org.hibernate.search.jpa.Search;
|
|||
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.mockito.Mockito;
|
||||
|
@ -125,6 +124,17 @@ public class BaseJpaTest {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
protected List<String> toUnqualifiedIdValues(IBundleProvider theFound) {
|
||||
List<String> retVal = new ArrayList<String>();
|
||||
int size = theFound.size();
|
||||
ourLog.info("Found {} results", size);
|
||||
List<IBaseResource> resources = theFound.getResources(0, size);
|
||||
for (IBaseResource next : resources) {
|
||||
retVal.add(next.getIdElement().toUnqualified().getValue());
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
protected String[] toValues(IIdType... theValues) {
|
||||
ArrayList<String> retVal = new ArrayList<String>();
|
||||
for (IIdType next : theValues) {
|
||||
|
|
|
@ -121,7 +121,7 @@ public class FhirSystemDaoDstu1Test extends BaseJpaTest {
|
|||
patient.setId(pid);
|
||||
IIdType newpid3 = ourPatientDao.update(patient, mySrd).getId();
|
||||
|
||||
IBundleProvider values = ourSystemDao.history(start, mySrd);
|
||||
IBundleProvider values = ourSystemDao.history(start, null, mySrd);
|
||||
assertEquals(4, values.size());
|
||||
|
||||
List<IBaseResource> res = values.getResources(0, 4);
|
||||
|
@ -140,10 +140,10 @@ public class FhirSystemDaoDstu1Test extends BaseJpaTest {
|
|||
|
||||
Thread.sleep(2000);
|
||||
|
||||
values = ourLocationDao.history(start, mySrd);
|
||||
values = ourLocationDao.history(start, null, mySrd);
|
||||
assertEquals(2, values.size());
|
||||
|
||||
values = ourLocationDao.history(lid.getIdPartAsLong(), start, mySrd);
|
||||
values = ourLocationDao.history(lid.toUnqualifiedVersionless(), start, null, mySrd);
|
||||
assertEquals(1, values.size());
|
||||
|
||||
}
|
||||
|
|
|
@ -98,7 +98,6 @@ import ca.uhn.fhir.rest.param.UriParam;
|
|||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
@ -34,7 +34,6 @@ import java.util.Set;
|
|||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.hamcrest.core.StringContains;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.BundleType;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.AfterClass;
|
||||
|
@ -829,7 +828,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
|
||||
@Test
|
||||
public void testDeleteResource() {
|
||||
int initialHistory = myPatientDao.history(null, mySrd).size();
|
||||
int initialHistory = myPatientDao.history(null, null, mySrd).size();
|
||||
|
||||
IIdType id1;
|
||||
IIdType id2;
|
||||
|
@ -871,7 +870,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
// good
|
||||
}
|
||||
|
||||
IBundleProvider history = myPatientDao.history(null, mySrd);
|
||||
IBundleProvider history = myPatientDao.history(null, null, mySrd);
|
||||
assertEquals(4 + initialHistory, history.size());
|
||||
List<IBaseResource> resources = history.getResources(0, 4);
|
||||
assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get((IResource) resources.get(0)));
|
||||
|
@ -953,7 +952,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
// ok
|
||||
}
|
||||
|
||||
IBundleProvider history = myPatientDao.history(id, null, mySrd);
|
||||
IBundleProvider history = myPatientDao.history(id, null, null, mySrd);
|
||||
assertEquals(2, history.size());
|
||||
|
||||
assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get((IResource) history.getResources(0, 1).get(0)));
|
||||
|
@ -1180,7 +1179,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
idv2 = myPatientDao.update(patient, mySrd).getId();
|
||||
}
|
||||
|
||||
List<Patient> patients = toList(myPatientDao.history(idv1.toVersionless(), null, mySrd));
|
||||
List<Patient> patients = toList(myPatientDao.history(idv1.toVersionless(), null, null, mySrd));
|
||||
assertTrue(patients.size() == 2);
|
||||
// Newest first
|
||||
assertEquals("Patient/testHistoryByForcedId/_history/2", patients.get(0).getId().toUnqualified().getValue());
|
||||
|
@ -1219,7 +1218,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
}
|
||||
|
||||
// By instance
|
||||
IBundleProvider history = myPatientDao.history(id, null, mySrd);
|
||||
IBundleProvider history = myPatientDao.history(id, null, null, mySrd);
|
||||
assertEquals(fullSize + 1, history.size());
|
||||
for (int i = 0; i < fullSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
|
@ -1228,7 +1227,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
}
|
||||
|
||||
// By type
|
||||
history = myPatientDao.history(null, mySrd);
|
||||
history = myPatientDao.history(null, null, mySrd);
|
||||
assertEquals(fullSize + 1, history.size());
|
||||
for (int i = 0; i < fullSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
|
@ -1237,7 +1236,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
}
|
||||
|
||||
// By server
|
||||
history = mySystemDao.history(null, mySrd);
|
||||
history = mySystemDao.history(null, null, mySrd);
|
||||
assertEquals(fullSize + 1, history.size());
|
||||
for (int i = 0; i < fullSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
|
@ -1250,7 +1249,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
*/
|
||||
|
||||
// By instance
|
||||
history = myPatientDao.history(id, middleDate, mySrd);
|
||||
history = myPatientDao.history(id, middleDate, null, mySrd);
|
||||
assertEquals(halfSize, history.size());
|
||||
for (int i = 0; i < halfSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
|
@ -1259,7 +1258,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
}
|
||||
|
||||
// By type
|
||||
history = myPatientDao.history(middleDate, mySrd);
|
||||
history = myPatientDao.history(middleDate, null, mySrd);
|
||||
assertEquals(halfSize, history.size());
|
||||
for (int i = 0; i < halfSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
|
@ -1268,7 +1267,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
}
|
||||
|
||||
// By server
|
||||
history = mySystemDao.history(middleDate, mySrd);
|
||||
history = mySystemDao.history(middleDate, null, mySrd);
|
||||
assertEquals(halfSize, history.size());
|
||||
for (int i = 0; i < halfSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
|
@ -1286,7 +1285,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
halfSize++;
|
||||
|
||||
// By instance
|
||||
history = myPatientDao.history(id, null, mySrd);
|
||||
history = myPatientDao.history(id, null, null, mySrd);
|
||||
for (int i = 0; i < fullSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
String actual = history.getResources(i, i + 1).get(0).getIdElement().getValue();
|
||||
|
@ -1295,7 +1294,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
assertEquals(log(history), fullSize + 1, history.size());
|
||||
|
||||
// By type
|
||||
history = myPatientDao.history(null, mySrd);
|
||||
history = myPatientDao.history(null, null, mySrd);
|
||||
for (int i = 0; i < fullSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
String actual = history.getResources(i, i + 1).get(0).getIdElement().getValue();
|
||||
|
@ -1306,7 +1305,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
assertEquals(log(history), fullSize + 1, history.size()); // fails?
|
||||
|
||||
// By server
|
||||
history = mySystemDao.history(null, mySrd);
|
||||
history = mySystemDao.history(null, null, mySrd);
|
||||
for (int i = 0; i < fullSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
String actual = history.getResources(i, i + 1).get(0).getIdElement().getValue();
|
||||
|
@ -1319,7 +1318,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
*/
|
||||
|
||||
// By instance
|
||||
history = myPatientDao.history(id, middleDate, mySrd);
|
||||
history = myPatientDao.history(id, middleDate, null, mySrd);
|
||||
for (int i = 0; i < halfSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
String actual = history.getResources(i, i + 1).get(0).getIdElement().getValue();
|
||||
|
@ -1328,7 +1327,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
assertEquals(halfSize, history.size());
|
||||
|
||||
// By type
|
||||
history = myPatientDao.history(middleDate, mySrd);
|
||||
history = myPatientDao.history(middleDate, null, mySrd);
|
||||
for (int i = 0; i < halfSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
String actual = history.getResources(i, i + 1).get(0).getIdElement().getValue();
|
||||
|
@ -1337,7 +1336,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
assertEquals(halfSize, history.size());
|
||||
|
||||
// By server
|
||||
history = mySystemDao.history(middleDate, mySrd);
|
||||
history = mySystemDao.history(middleDate, null, mySrd);
|
||||
for (int i = 0; i < halfSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
String actual = history.getResources(i, i + 1).get(0).getIdElement().getValue();
|
||||
|
@ -1359,7 +1358,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
patient.setId(id);
|
||||
myPatientDao.update(patient, mySrd);
|
||||
|
||||
IBundleProvider history = myPatientDao.history(id, null, mySrd);
|
||||
IBundleProvider history = myPatientDao.history(id, null, null, mySrd);
|
||||
assertEquals(3, history.size());
|
||||
List<IBaseResource> entries = history.getResources(0, 3);
|
||||
ourLog.info("" + ResourceMetadataKeyEnum.UPDATED.get((IResource) entries.get(0)));
|
||||
|
|
|
@ -111,7 +111,7 @@ public class FhirResourceDaoDstu2UpdateTest extends BaseJpaDstu2Test {
|
|||
* Get history
|
||||
*/
|
||||
|
||||
IBundleProvider historyBundle = myPatientDao.history(outcome.getId(), null, mySrd);
|
||||
IBundleProvider historyBundle = myPatientDao.history(outcome.getId(), null, null, mySrd);
|
||||
|
||||
assertEquals(2, historyBundle.size());
|
||||
|
||||
|
|
|
@ -835,7 +835,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2SystemTest {
|
|||
// ok
|
||||
}
|
||||
|
||||
IBundleProvider history = myPatientDao.history(id, null, mySrd);
|
||||
IBundleProvider history = myPatientDao.history(id, null, null, mySrd);
|
||||
assertEquals(2, history.size());
|
||||
|
||||
assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get((IResource) history.getResources(0, 1).get(0)));
|
||||
|
|
|
@ -85,6 +85,8 @@ import org.junit.Ignore;
|
|||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
|
||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
|
@ -1124,7 +1126,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
|
||||
@Test
|
||||
public void testDeleteResource() {
|
||||
int initialHistory = myPatientDao.history(null, mySrd).size();
|
||||
int initialHistory = myPatientDao.history((Date)null, null, mySrd).size();
|
||||
|
||||
IIdType id1;
|
||||
IIdType id2;
|
||||
|
@ -1166,7 +1168,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
// good
|
||||
}
|
||||
|
||||
IBundleProvider history = myPatientDao.history(null, mySrd);
|
||||
IBundleProvider history = myPatientDao.history((Date)null, null, mySrd);
|
||||
assertEquals(4 + initialHistory, history.size());
|
||||
List<IBaseResource> resources = history.getResources(0, 4);
|
||||
assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get((IAnyResource) resources.get(0)));
|
||||
|
@ -1246,7 +1248,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
// ok
|
||||
}
|
||||
|
||||
IBundleProvider history = myPatientDao.history(id, null, mySrd);
|
||||
IBundleProvider history = myPatientDao.history(id, null, null, mySrd);
|
||||
assertEquals(2, history.size());
|
||||
|
||||
assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get((IAnyResource) history.getResources(0, 1).get(0)));
|
||||
|
@ -1470,7 +1472,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
idv2 = myPatientDao.update(patient, mySrd).getId();
|
||||
}
|
||||
|
||||
List<Patient> patients = toList(myPatientDao.history(idv1.toVersionless(), null, mySrd));
|
||||
List<Patient> patients = toList(myPatientDao.history(idv1.toVersionless(), null, null, mySrd));
|
||||
assertTrue(patients.size() == 2);
|
||||
// Newest first
|
||||
assertEquals("Patient/testHistoryByForcedId/_history/2", patients.get(0).getIdElement().toUnqualified().getValue());
|
||||
|
@ -1478,6 +1480,36 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
assertNotEquals(idv1, idv2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHistoryWithFromAndTo() throws Exception {
|
||||
String methodName = "testHistoryWithFromAndTo";
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().addFamily(methodName);
|
||||
IIdType id = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
List<Date> preDates = Lists.newArrayList();
|
||||
List<String> ids = Lists.newArrayList();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Thread.sleep(10);
|
||||
preDates.add(new Date());
|
||||
patient.setId(id);
|
||||
patient.getName().get(0).getFamily().get(0).setValue(methodName + "_i");
|
||||
ids.add(myPatientDao.update(patient, mySrd).getId().toUnqualified().getValue());
|
||||
}
|
||||
|
||||
List<String> idValues;
|
||||
|
||||
idValues = toUnqualifiedIdValues(myPatientDao.history(id, preDates.get(0), preDates.get(3), mySrd));
|
||||
assertThat(idValues, contains(ids.get(2), ids.get(1), ids.get(0)));
|
||||
|
||||
idValues = toUnqualifiedIdValues(myPatientDao.history(preDates.get(0), preDates.get(3), mySrd));
|
||||
assertThat(idValues, contains(ids.get(2), ids.get(1), ids.get(0)));
|
||||
|
||||
idValues = toUnqualifiedIdValues(mySystemDao.history(preDates.get(0), preDates.get(3), mySrd));
|
||||
assertThat(idValues, contains(ids.get(2), ids.get(1), ids.get(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHistoryOverMultiplePages() throws Exception {
|
||||
String methodName = "testHistoryOverMultiplePages";
|
||||
|
@ -1502,7 +1534,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
}
|
||||
|
||||
// By instance
|
||||
IBundleProvider history = myPatientDao.history(id, null, mySrd);
|
||||
IBundleProvider history = myPatientDao.history(id, null, null, mySrd);
|
||||
assertEquals(fullSize + 1, history.size());
|
||||
for (int i = 0; i < fullSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
|
@ -1511,7 +1543,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
}
|
||||
|
||||
// By type
|
||||
history = myPatientDao.history(null, mySrd);
|
||||
history = myPatientDao.history((Date)null, null, mySrd);
|
||||
assertEquals(fullSize + 1, history.size());
|
||||
for (int i = 0; i < fullSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
|
@ -1520,7 +1552,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
}
|
||||
|
||||
// By server
|
||||
history = mySystemDao.history(null, mySrd);
|
||||
history = mySystemDao.history(null, null, mySrd);
|
||||
assertEquals(fullSize + 1, history.size());
|
||||
for (int i = 0; i < fullSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
|
@ -1533,7 +1565,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
*/
|
||||
|
||||
// By instance
|
||||
history = myPatientDao.history(id, middleDate, mySrd);
|
||||
history = myPatientDao.history(id, middleDate, null, mySrd);
|
||||
assertEquals(halfSize, history.size());
|
||||
for (int i = 0; i < halfSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
|
@ -1542,7 +1574,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
}
|
||||
|
||||
// By type
|
||||
history = myPatientDao.history(middleDate, mySrd);
|
||||
history = myPatientDao.history(middleDate, null, mySrd);
|
||||
assertEquals(halfSize, history.size());
|
||||
for (int i = 0; i < halfSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
|
@ -1551,7 +1583,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
}
|
||||
|
||||
// By server
|
||||
history = mySystemDao.history(middleDate, mySrd);
|
||||
history = mySystemDao.history(middleDate, null, mySrd);
|
||||
assertEquals(halfSize, history.size());
|
||||
for (int i = 0; i < halfSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
|
@ -1569,7 +1601,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
halfSize++;
|
||||
|
||||
// By instance
|
||||
history = myPatientDao.history(id, null, mySrd);
|
||||
history = myPatientDao.history(id, null, null, mySrd);
|
||||
assertEquals(fullSize + 1, history.size());
|
||||
for (int i = 0; i < fullSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
|
@ -1578,7 +1610,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
}
|
||||
|
||||
// By type
|
||||
history = myPatientDao.history(null, mySrd);
|
||||
history = myPatientDao.history((Date)null, null, mySrd);
|
||||
assertEquals(fullSize + 1, history.size());
|
||||
for (int i = 0; i < fullSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
|
@ -1587,7 +1619,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
}
|
||||
|
||||
// By server
|
||||
history = mySystemDao.history(null, mySrd);
|
||||
history = mySystemDao.history(null, null, mySrd);
|
||||
assertEquals(fullSize + 1, history.size());
|
||||
for (int i = 0; i < fullSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
|
@ -1600,7 +1632,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
*/
|
||||
|
||||
// By instance
|
||||
history = myPatientDao.history(id, middleDate, mySrd);
|
||||
history = myPatientDao.history(id, middleDate, null, mySrd);
|
||||
assertEquals(halfSize, history.size());
|
||||
for (int i = 0; i < halfSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
|
@ -1609,7 +1641,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
}
|
||||
|
||||
// By type
|
||||
history = myPatientDao.history(middleDate, mySrd);
|
||||
history = myPatientDao.history(middleDate, null, mySrd);
|
||||
assertEquals(halfSize, history.size());
|
||||
for (int i = 0; i < halfSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
|
@ -1618,7 +1650,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
}
|
||||
|
||||
// By server
|
||||
history = mySystemDao.history(middleDate, mySrd);
|
||||
history = mySystemDao.history(middleDate, null, mySrd);
|
||||
assertEquals(halfSize, history.size());
|
||||
for (int i = 0; i < halfSize; i++) {
|
||||
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
|
||||
|
@ -1644,7 +1676,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
|
||||
// No since
|
||||
|
||||
IBundleProvider history = myPatientDao.history(null, mySrd);
|
||||
IBundleProvider history = myPatientDao.history((Date)null, null, mySrd);
|
||||
assertEquals(1, history.size());
|
||||
Patient outPatient = (Patient) history.getResources(0, 1).get(0);
|
||||
assertEquals("version1", inPatient.getName().get(0).getFamilyAsSingleString());
|
||||
|
@ -1653,7 +1685,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
|
||||
// Before since
|
||||
|
||||
history = myPatientDao.history(before, mySrd);
|
||||
history = myPatientDao.history(before, null, mySrd);
|
||||
assertEquals(1, history.size());
|
||||
outPatient = (Patient) history.getResources(0, 1).get(0);
|
||||
assertEquals("version1", inPatient.getName().get(0).getFamilyAsSingleString());
|
||||
|
@ -1662,7 +1694,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
|
||||
// After since
|
||||
|
||||
history = myPatientDao.history(after, mySrd);
|
||||
history = myPatientDao.history(after, null, mySrd);
|
||||
assertEquals(0, history.size());
|
||||
|
||||
}
|
||||
|
@ -1674,7 +1706,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
inPatient.getMeta().addProfile("http://example.com/1");
|
||||
IIdType id = myPatientDao.create(inPatient, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
IBundleProvider history = myPatientDao.history(null, mySrd);
|
||||
IBundleProvider history = myPatientDao.history((Date)null, null, mySrd);
|
||||
assertEquals(1, history.size());
|
||||
Patient outPatient = (Patient) history.getResources(0, 1).get(0);
|
||||
assertEquals("version1", inPatient.getName().get(0).getFamilyAsSingleString());
|
||||
|
@ -1688,7 +1720,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
inPatient.getMeta().addProfile("http://example.com/2");
|
||||
myPatientDao.metaAddOperation(id, inPatient.getMeta(), mySrd);
|
||||
|
||||
history = myPatientDao.history(null, mySrd);
|
||||
history = myPatientDao.history((Date)null, null, mySrd);
|
||||
assertEquals(1, history.size());
|
||||
outPatient = (Patient) history.getResources(0, 1).get(0);
|
||||
assertEquals("version1", inPatient.getName().get(0).getFamilyAsSingleString());
|
||||
|
@ -1704,7 +1736,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
inPatient.getName().get(0).addFamily("version2");
|
||||
myPatientDao.update(inPatient, mySrd);
|
||||
|
||||
history = myPatientDao.history(null, mySrd);
|
||||
history = myPatientDao.history((Date)null, null, mySrd);
|
||||
assertEquals(2, history.size());
|
||||
outPatient = (Patient) history.getResources(0, 2).get(0);
|
||||
assertEquals("version1 version2", outPatient.getName().get(0).getFamilyAsSingleString());
|
||||
|
@ -1730,7 +1762,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
patient.setId(id);
|
||||
myPatientDao.update(patient, mySrd);
|
||||
|
||||
IBundleProvider history = myPatientDao.history(id, null, mySrd);
|
||||
IBundleProvider history = myPatientDao.history(id, null, null, mySrd);
|
||||
List<IBaseResource> entries = history.getResources(0, 3);
|
||||
ourLog.info(((IAnyResource) entries.get(0)).getIdElement() + " - " + ((IAnyResource) entries.get(0)).getMeta().getLastUpdated());
|
||||
ourLog.info(((IAnyResource) entries.get(1)).getIdElement() + " - " + ((IAnyResource) entries.get(1)).getMeta().getLastUpdated());
|
||||
|
@ -1754,7 +1786,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
@Test
|
||||
public void testHistoryWithInvalidId() throws Exception {
|
||||
try {
|
||||
myPatientDao.history(new IdDt("Patient/FOOFOOFOO"), null, mySrd);
|
||||
myPatientDao.history(new IdDt("Patient/FOOFOOFOO"), null, null, mySrd);
|
||||
fail();
|
||||
} catch (ResourceNotFoundException e) {
|
||||
assertEquals("Resource Patient/FOOFOOFOO is not known", e.getMessage());
|
||||
|
|
|
@ -107,7 +107,7 @@ public class FhirResourceDaoDstu3UpdateTest extends BaseJpaDstu3Test {
|
|||
* Get history
|
||||
*/
|
||||
|
||||
IBundleProvider historyBundle = myPatientDao.history(outcome.getId(), null, mySrd);
|
||||
IBundleProvider historyBundle = myPatientDao.history(outcome.getId(), null, null, mySrd);
|
||||
|
||||
assertEquals(2, historyBundle.size());
|
||||
|
||||
|
|
|
@ -1059,7 +1059,7 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
|||
// ok
|
||||
}
|
||||
|
||||
IBundleProvider history = myPatientDao.history(id, null, mySrd);
|
||||
IBundleProvider history = myPatientDao.history(id, null, null, mySrd);
|
||||
assertEquals(2, history.size());
|
||||
|
||||
assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get((IAnyResource) history.getResources(0, 1).get(0)));
|
||||
|
|
|
@ -279,8 +279,8 @@ public class SystemProviderDstu2Test extends BaseJpaDstu2Test {
|
|||
|
||||
@Test
|
||||
public void testGetOperationDefinition() {
|
||||
OperationDefinition op = ourClient.read(OperationDefinition.class, "get-resource-counts");
|
||||
assertEquals("$get-resource-counts", op.getCode());
|
||||
OperationDefinition op = ourClient.read(OperationDefinition.class, "-s-get-resource-counts");
|
||||
assertEquals("get-resource-counts", op.getCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -100,6 +100,7 @@ import org.junit.Test;
|
|||
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.model.primitive.UriDt;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.SummaryEnum;
|
||||
|
@ -1868,7 +1869,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
|||
ourLog.info(value.getTime() + "");
|
||||
ourLog.info(before.getTime() + "");
|
||||
assertTrue(value.after(before));
|
||||
assertTrue(value.before(after));
|
||||
assertTrue(new InstantDt(value) + " should be before " + new InstantDt(after), value.before(after));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -453,7 +453,7 @@ public class SystemProviderDstu3Test extends BaseJpaDstu3Test {
|
|||
|
||||
@Test
|
||||
public void testGetOperationDefinition() {
|
||||
OperationDefinition op = ourClient.read(OperationDefinition.class, "get-resource-counts");
|
||||
OperationDefinition op = ourClient.read(OperationDefinition.class, "-s-get-resource-counts");
|
||||
assertEquals("get-resource-counts", op.getCode());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
package ca.uhn.fhir.rest.param;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
|
||||
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
|
@ -31,6 +34,23 @@ public class DateRangeParamTest {
|
|||
return new DateRangeParam(new DateParam(theString));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRangeFromDates() {
|
||||
TimeZone tz = TimeZone.getDefault();
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("America/Toronto"));
|
||||
try {
|
||||
Date startDate = new InstantDt("2010-01-01T00:00:00.000Z").getValue();
|
||||
Date endDate = new InstantDt("2010-01-01T00:00:00.001Z").getValue();
|
||||
DateTimeDt startDateTime = new DateTimeDt(startDate, TemporalPrecisionEnum.MILLI);
|
||||
DateTimeDt endDateTime = new DateTimeDt(endDate, TemporalPrecisionEnum.MILLI);
|
||||
|
||||
DateRangeParam range = new DateRangeParam(startDateTime, endDateTime);
|
||||
assertEquals("2009-12-31T19:00:00.000-05:00", range.getValuesAsQueryTokens().get(0).getValueAsString());
|
||||
} finally {
|
||||
TimeZone.setDefault(tz);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRange() {
|
||||
InstantDt start = new InstantDt("2015-09-23T07:43:34.811-04:00");
|
||||
|
@ -41,8 +61,7 @@ public class DateRangeParamTest {
|
|||
assertEquals(QuantityCompararatorEnum.LESSTHAN, upperBound.getComparator());
|
||||
|
||||
/*
|
||||
* When DateParam (which extends DateTimeDt) gets passed in, make sure we preserve the
|
||||
* comparators..
|
||||
* When DateParam (which extends DateTimeDt) gets passed in, make sure we preserve the comparators..
|
||||
*/
|
||||
DateRangeParam param = new DateRangeParam(lowerBound, upperBound);
|
||||
ourLog.info(param.toString());
|
||||
|
@ -169,7 +188,6 @@ public class DateRangeParamTest {
|
|||
return new Date(ourFmt.parse(theString).getTime() - 1L);
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
|
@ -49,12 +50,17 @@ import ca.uhn.fhir.util.TestUtil;
|
|||
|
||||
public class PlainProviderTest {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(PlainProviderTest.class);
|
||||
private int myPort;
|
||||
private Server myServer;
|
||||
private CloseableHttpClient myClient;
|
||||
private static final FhirContext ourCtx = FhirContext.forDstu1();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(PlainProviderTest.class);
|
||||
private CloseableHttpClient myClient;
|
||||
private int myPort;
|
||||
private RestfulServer myRestfulServer;
|
||||
private Server myServer;
|
||||
|
||||
@After
|
||||
public void after() throws Exception {
|
||||
myServer.stop();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
|
@ -76,9 +82,60 @@ public class PlainProviderTest {
|
|||
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() throws Exception {
|
||||
myServer.stop();
|
||||
@Test
|
||||
public void testGlobalHistory() throws Exception {
|
||||
GlobalHistoryProvider provider = new GlobalHistoryProvider();
|
||||
myRestfulServer.setProviders(provider);
|
||||
myServer.start();
|
||||
|
||||
String baseUri = "http://localhost:" + myPort + "/fhir/context";
|
||||
HttpResponse status = myClient.execute(new HttpGet(baseUri + "/_history?_since=2012-01-02T00%3A01%3A02&_count=12"));
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
|
||||
assertEquals(3, bundle.getEntries().size());
|
||||
|
||||
assertThat(provider.myLastSince.getValueAsString(), StringStartsWith.startsWith("2012-01-02T00:01:02"));
|
||||
assertThat(provider.myLastCount.getValueAsString(), IsEqual.equalTo("12"));
|
||||
|
||||
status = myClient.execute(new HttpGet(baseUri + "/_history?&_count=12"));
|
||||
responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
bundle = ourCtx.newXmlParser().parseBundle(responseContent);
|
||||
assertEquals(3, bundle.getEntries().size());
|
||||
assertNull(provider.myLastSince);
|
||||
assertThat(provider.myLastCount.getValueAsString(), IsEqual.equalTo("12"));
|
||||
|
||||
status =myClient.execute(new HttpGet(baseUri + "/_history?_since=2012-01-02T00%3A01%3A02"));
|
||||
responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
bundle = ourCtx.newXmlParser().parseBundle(responseContent);
|
||||
assertEquals(3, bundle.getEntries().size());
|
||||
assertThat(provider.myLastSince.getValueAsString(), StringStartsWith.startsWith("2012-01-02T00:01:02"));
|
||||
assertNull(provider.myLastCount);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGlobalHistoryNoParams() throws Exception {
|
||||
GlobalHistoryProvider provider = new GlobalHistoryProvider();
|
||||
myRestfulServer.setProviders(provider);
|
||||
myServer.start();
|
||||
|
||||
String baseUri = "http://localhost:" + myPort + "/fhir/context";
|
||||
CloseableHttpResponse status = myClient.execute(new HttpGet(baseUri + "/_history"));
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
|
||||
assertEquals(3, bundle.getEntries().size());
|
||||
assertNull(provider.myLastSince);
|
||||
assertNull(provider.myLastCount);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -109,110 +166,40 @@ public class PlainProviderTest {
|
|||
httpGet.releaseConnection();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGlobalHistory() throws Exception {
|
||||
GlobalHistoryProvider provider = new GlobalHistoryProvider();
|
||||
myRestfulServer.setProviders(provider);
|
||||
myServer.start();
|
||||
|
||||
String baseUri = "http://localhost:" + myPort + "/fhir/context";
|
||||
HttpResponse status = myClient.execute(new HttpGet(baseUri + "/_history?_since=2012-01-02T00%3A01%3A02&_count=12"));
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
|
||||
assertEquals(3, bundle.getEntries().size());
|
||||
|
||||
assertThat(provider.myLastSince.getValueAsString(), StringStartsWith.startsWith("2012-01-02T00:01:02"));
|
||||
assertThat(provider.myLastCount.getValueAsString(), IsEqual.equalTo("12"));
|
||||
|
||||
status = myClient.execute(new HttpGet(baseUri + "/_history?&_count=12"));
|
||||
responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
bundle = ourCtx.newXmlParser().parseBundle(responseContent);
|
||||
assertEquals(3, bundle.getEntries().size());
|
||||
assertNull(provider.myLastSince.getValueAsString());
|
||||
assertThat(provider.myLastCount.getValueAsString(), IsEqual.equalTo("12"));
|
||||
|
||||
status =myClient.execute(new HttpGet(baseUri + "/_history?_since=2012-01-02T00%3A01%3A02"));
|
||||
responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
bundle = ourCtx.newXmlParser().parseBundle(responseContent);
|
||||
assertEquals(3, bundle.getEntries().size());
|
||||
assertThat(provider.myLastSince.getValueAsString(), StringStartsWith.startsWith("2012-01-02T00:01:02"));
|
||||
assertNull(provider.myLastCount.getValueAsString());
|
||||
|
||||
status =myClient.execute(new HttpGet(baseUri + "/_history"));
|
||||
responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
bundle = ourCtx.newXmlParser().parseBundle(responseContent);
|
||||
assertEquals(3, bundle.getEntries().size());
|
||||
assertNull(provider.myLastSince.getValueAsString());
|
||||
assertNull(provider.myLastCount.getValueAsString());
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
*/
|
||||
public static class SearchProvider {
|
||||
|
||||
public Map<String, Patient> getIdToPatient() {
|
||||
Map<String, Patient> idToPatient = new HashMap<String, Patient>();
|
||||
{
|
||||
Patient patient = createPatient();
|
||||
idToPatient.put("1", patient);
|
||||
}
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.getIdentifier().add(new IdentifierDt());
|
||||
patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL);
|
||||
patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns"));
|
||||
patient.getIdentifier().get(0).setValue("00002");
|
||||
patient.getName().add(new HumanNameDt());
|
||||
patient.getName().get(0).addFamily("Test");
|
||||
patient.getName().get(0).addGiven("PatientTwo");
|
||||
patient.getGender().setText("F");
|
||||
idToPatient.put("2", patient);
|
||||
}
|
||||
return idToPatient;
|
||||
}
|
||||
|
||||
@Search(type = Patient.class)
|
||||
public Patient findPatient(@RequiredParam(name = Patient.SP_IDENTIFIER) IdentifierDt theIdentifier) {
|
||||
for (Patient next : getIdToPatient().values()) {
|
||||
for (IdentifierDt nextId : next.getIdentifier()) {
|
||||
if (nextId.matchesSystemAndValue(theIdentifier)) {
|
||||
return next;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the resource by its identifier
|
||||
*
|
||||
* @param theId
|
||||
* The resource identity
|
||||
* @return The resource
|
||||
*/
|
||||
@Read(type = Patient.class)
|
||||
public Patient getPatientById(@IdParam IdDt theId) {
|
||||
return getIdToPatient().get(theId.getValue());
|
||||
}
|
||||
private static Organization createOrganization() {
|
||||
Organization retVal = new Organization();
|
||||
retVal.setId("1");
|
||||
retVal.addIdentifier();
|
||||
retVal.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL);
|
||||
retVal.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns"));
|
||||
retVal.getIdentifier().get(0).setValue("00001");
|
||||
retVal.getName().setValue("Test Org");
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private static Patient createPatient() {
|
||||
Patient patient = new Patient();
|
||||
patient.setId("1");
|
||||
patient.addIdentifier();
|
||||
patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL);
|
||||
patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns"));
|
||||
patient.getIdentifier().get(0).setValue("00001");
|
||||
patient.addName();
|
||||
patient.getName().get(0).addFamily("Test");
|
||||
patient.getName().get(0).addGiven("PatientOne");
|
||||
patient.getGender().setText("M");
|
||||
return patient;
|
||||
}
|
||||
|
||||
public static class GlobalHistoryProvider {
|
||||
|
||||
private InstantDt myLastSince;
|
||||
private IntegerDt myLastCount;
|
||||
private InstantDt myLastSince;
|
||||
|
||||
@History
|
||||
public List<IResource> getGlobalHistory(@Since InstantDt theSince, @Count IntegerDt theCount) {
|
||||
|
@ -246,35 +233,54 @@ public class PlainProviderTest {
|
|||
|
||||
}
|
||||
|
||||
private static Patient createPatient() {
|
||||
Patient patient = new Patient();
|
||||
patient.setId("1");
|
||||
patient.addIdentifier();
|
||||
patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL);
|
||||
patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns"));
|
||||
patient.getIdentifier().get(0).setValue("00001");
|
||||
patient.addName();
|
||||
patient.getName().get(0).addFamily("Test");
|
||||
patient.getName().get(0).addGiven("PatientOne");
|
||||
patient.getGender().setText("M");
|
||||
return patient;
|
||||
}
|
||||
|
||||
private static Organization createOrganization() {
|
||||
Organization retVal = new Organization();
|
||||
retVal.setId("1");
|
||||
retVal.addIdentifier();
|
||||
retVal.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL);
|
||||
retVal.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns"));
|
||||
retVal.getIdentifier().get(0).setValue("00001");
|
||||
retVal.getName().setValue("Test Org");
|
||||
return retVal;
|
||||
}
|
||||
public static class SearchProvider {
|
||||
|
||||
@Search(type = Patient.class)
|
||||
public Patient findPatient(@RequiredParam(name = Patient.SP_IDENTIFIER) IdentifierDt theIdentifier) {
|
||||
for (Patient next : getIdToPatient().values()) {
|
||||
for (IdentifierDt nextId : next.getIdentifier()) {
|
||||
if (nextId.matchesSystemAndValue(theIdentifier)) {
|
||||
return next;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Map<String, Patient> getIdToPatient() {
|
||||
Map<String, Patient> idToPatient = new HashMap<String, Patient>();
|
||||
{
|
||||
Patient patient = createPatient();
|
||||
idToPatient.put("1", patient);
|
||||
}
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.getIdentifier().add(new IdentifierDt());
|
||||
patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL);
|
||||
patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns"));
|
||||
patient.getIdentifier().get(0).setValue("00002");
|
||||
patient.getName().add(new HumanNameDt());
|
||||
patient.getName().get(0).addFamily("Test");
|
||||
patient.getName().get(0).addGiven("PatientTwo");
|
||||
patient.getGender().setText("F");
|
||||
idToPatient.put("2", patient);
|
||||
}
|
||||
return idToPatient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the resource by its identifier
|
||||
*
|
||||
* @param theId
|
||||
* The resource identity
|
||||
* @return The resource
|
||||
*/
|
||||
@Read(type = Patient.class)
|
||||
public Patient getPatientById(@IdParam IdDt theId) {
|
||||
return getIdToPatient().get(theId.getValue());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -163,14 +163,14 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
|||
retVal.append(theMethodBinding.getResourceName());
|
||||
}
|
||||
|
||||
retVal.append('_');
|
||||
retVal.append('-');
|
||||
if (theMethodBinding.isCanOperateAtInstanceLevel()) {
|
||||
retVal.append('i');
|
||||
}
|
||||
if (theMethodBinding.isCanOperateAtServerLevel()) {
|
||||
retVal.append('s');
|
||||
}
|
||||
retVal.append('_');
|
||||
retVal.append('-');
|
||||
|
||||
// Exclude the leading $
|
||||
retVal.append(theMethodBinding.getName(), 1, theMethodBinding.getName().length());
|
||||
|
@ -318,7 +318,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
|||
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
|
||||
String opName = myOperationBindingToName.get(methodBinding);
|
||||
if (operationNames.add(opName)) {
|
||||
rest.addOperation().setName(methodBinding.getName()).getDefinition().setReference("OperationDefinition/" + opName);
|
||||
rest.addOperation().setName(methodBinding.getName().substring(1)).getDefinition().setReference("OperationDefinition/" + opName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,15 +3,12 @@ package ca.uhn.fhir.model.primitive;
|
|||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.either;
|
||||
import static org.hamcrest.Matchers.endsWith;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
|
@ -36,30 +33,15 @@ public class BaseDateTimeDtDstu2Test {
|
|||
private static Locale ourDefaultLocale;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseDateTimeDtDstu2Test.class);
|
||||
|
||||
|
||||
|
||||
private SimpleDateFormat myDateInstantParser;
|
||||
|
||||
|
||||
private FastDateFormat myDateInstantZoneParser;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
myDateInstantParser = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
|
||||
myDateInstantZoneParser = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSSZ", TimeZone.getTimeZone("GMT-02:00"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeZeroOffset() {
|
||||
DateTimeDt dt = new DateTimeDt();
|
||||
dt.setValueAsString("2011-01-01T12:00:00-04:00");
|
||||
dt.setTimeZone(TimeZone.getTimeZone("GMT-0:00"));
|
||||
|
||||
String val = dt.getValueAsString();
|
||||
assertEquals("2011-01-01T16:00:00+00:00", val);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void setTimezoneToZulu() {
|
||||
DateTimeDt dt = new DateTimeDt(new Date(816411488000L));
|
||||
|
@ -87,6 +69,37 @@ public class BaseDateTimeDtDstu2Test {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateFormatsInvalid() {
|
||||
// No spaces in dates
|
||||
verifyFails("1974 12-25");
|
||||
verifyFails("1974-12 25");
|
||||
|
||||
// No letters
|
||||
verifyFails("A974-12-25");
|
||||
verifyFails("1974-A2-25");
|
||||
verifyFails("1974-12-A5");
|
||||
|
||||
// Date shouldn't have a time zone
|
||||
verifyFails("1974-12-25Z");
|
||||
verifyFails("1974-12-25+10:00");
|
||||
|
||||
// Out of range
|
||||
verifyFails("1974-13-25");
|
||||
verifyFails("1974-12-32");
|
||||
verifyFails("2015-02-29");
|
||||
verifyFails("-016-02-01");
|
||||
verifyFails("2016--2-01");
|
||||
verifyFails("2016-02--1");
|
||||
|
||||
// Invalid length
|
||||
verifyFails("2");
|
||||
verifyFails("20");
|
||||
verifyFails("201");
|
||||
verifyFails("2016-0");
|
||||
verifyFails("2016-02-0");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for #57
|
||||
*/
|
||||
|
@ -112,6 +125,46 @@ public class BaseDateTimeDtDstu2Test {
|
|||
assertThat(outcomeStr, containsString("date-primitive"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateTimeFormatsInvalid() {
|
||||
// Bad timezone
|
||||
verifyFails("1974-12-01T00:00:00A");
|
||||
verifyFails("1974-12-01T00:00:00=00:00");
|
||||
verifyFails("1974-12-01T00:00:00+");
|
||||
verifyFails("1974-12-01T00:00:00+25:00");
|
||||
verifyFails("1974-12-01T00:00:00+00:61");
|
||||
verifyFails("1974-12-01T00:00:00+00 401");
|
||||
verifyFails("1974-12-01T00:00:00+0");
|
||||
verifyFails("1974-12-01T00:00:00+01");
|
||||
verifyFails("1974-12-01T00:00:00+011");
|
||||
verifyFails("1974-12-01T00:00:00+0110");
|
||||
|
||||
// Out of range
|
||||
verifyFails("1974-12-25T25:00:00Z");
|
||||
verifyFails("1974-12-25T24:00:00Z");
|
||||
verifyFails("1974-12-25T23:60:00Z");
|
||||
verifyFails("1974-12-25T23:59:60Z");
|
||||
|
||||
// Invalid Separators
|
||||
verifyFails("1974-12-25T23 59:00Z");
|
||||
verifyFails("1974-12-25T23:59 00Z");
|
||||
|
||||
// Invalid length
|
||||
verifyFails("1974-12-25T2Z");
|
||||
verifyFails("1974-12-25T22:Z");
|
||||
verifyFails("1974-12-25T22:1Z");
|
||||
verifyFails("1974-12-25T22:11:Z");
|
||||
verifyFails("1974-12-25T22:11:1Z");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateTimeFormatsInvalidMillis() {
|
||||
verifyFails("1974-12-01T00:00:00.AZ");
|
||||
verifyFails("1974-12-01T00:00:00.-Z");
|
||||
verifyFails("1974-12-01T00:00:00.-1Z");
|
||||
verifyFails("1974-12-01T00:00:00..1111Z");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateTimeInLocalTimezone() {
|
||||
DateTimeDt dt = DateTimeDt.withCurrentTime();
|
||||
|
@ -128,6 +181,28 @@ public class BaseDateTimeDtDstu2Test {
|
|||
assertThat(offset, either(endsWith("-05:00")).or(endsWith("-04:00")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeZeroOffset() {
|
||||
DateTimeDt dt = new DateTimeDt();
|
||||
dt.setValueAsString("2011-01-01T12:00:00-04:00");
|
||||
dt.setTimeZone(TimeZone.getTimeZone("GMT-0:00"));
|
||||
|
||||
String val = dt.getValueAsString();
|
||||
assertEquals("2011-01-01T16:00:00+00:00", val);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValueAsCalendar() {
|
||||
assertNull(new InstantDt().getValueAsCalendar());
|
||||
|
||||
InstantDt dt = new InstantDt("2011-01-03T07:11:22.002-08:00");
|
||||
GregorianCalendar cal = dt.getValueAsCalendar();
|
||||
|
||||
assertEquals(2011, cal.get(Calendar.YEAR));
|
||||
assertEquals(7, cal.get(Calendar.HOUR_OF_DAY));
|
||||
assertEquals(2, cal.get(Calendar.MILLISECOND));
|
||||
assertEquals("GMT-08:00", cal.getTimeZone().getID());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstantInLocalTimezone() {
|
||||
|
@ -163,17 +238,16 @@ public class BaseDateTimeDtDstu2Test {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testParseDate() {
|
||||
new DateDt("2012-03-31");
|
||||
public void testNewInstance() throws InterruptedException {
|
||||
InstantDt now = InstantDt.withCurrentTime();
|
||||
Thread.sleep(100);
|
||||
InstantDt then = InstantDt.withCurrentTime();
|
||||
assertTrue(now.getValue().before(then.getValue()));
|
||||
}
|
||||
|
||||
/*
|
||||
* Just to be lenient
|
||||
*/
|
||||
@Test
|
||||
public void testParseIgnoresLeadingAndTrailingSpace() {
|
||||
DateTimeDt dt = new DateTimeDt(" 2014-10-11T12:11:00Z ");
|
||||
assertEquals("2014-10-11 10:11:00.000-0200", myDateInstantZoneParser.format(dt.getValue()));
|
||||
public void testParseDate() {
|
||||
new DateDt("2012-03-31");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -231,95 +305,13 @@ public class BaseDateTimeDtDstu2Test {
|
|||
validateMillisPartial("2015-06-22T00:00:00.00123Z", 1);
|
||||
}
|
||||
|
||||
private void validateMillisPartial(String input, int expected) {
|
||||
InstantDt dt = new InstantDt();
|
||||
dt.setValueAsString(input);
|
||||
Date date = dt.getValue();
|
||||
|
||||
assertEquals(expected, date.getTime() % 1000);
|
||||
}
|
||||
|
||||
/*
|
||||
* Just to be lenient
|
||||
*/
|
||||
@Test
|
||||
public void testDateTimeFormatsInvalidMillis() {
|
||||
verifyFails("1974-12-01T00:00:00.AZ");
|
||||
verifyFails("1974-12-01T00:00:00.-Z");
|
||||
verifyFails("1974-12-01T00:00:00.-1Z");
|
||||
verifyFails("1974-12-01T00:00:00..1111Z");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateTimeFormatsInvalid() {
|
||||
// Bad timezone
|
||||
verifyFails("1974-12-01T00:00:00A");
|
||||
verifyFails("1974-12-01T00:00:00=00:00");
|
||||
verifyFails("1974-12-01T00:00:00+");
|
||||
verifyFails("1974-12-01T00:00:00+25:00");
|
||||
verifyFails("1974-12-01T00:00:00+00:61");
|
||||
verifyFails("1974-12-01T00:00:00+00 401");
|
||||
verifyFails("1974-12-01T00:00:00+0");
|
||||
verifyFails("1974-12-01T00:00:00+01");
|
||||
verifyFails("1974-12-01T00:00:00+011");
|
||||
verifyFails("1974-12-01T00:00:00+0110");
|
||||
|
||||
// Out of range
|
||||
verifyFails("1974-12-25T25:00:00Z");
|
||||
verifyFails("1974-12-25T24:00:00Z");
|
||||
verifyFails("1974-12-25T23:60:00Z");
|
||||
verifyFails("1974-12-25T23:59:60Z");
|
||||
|
||||
// Invalid Separators
|
||||
verifyFails("1974-12-25T23 59:00Z");
|
||||
verifyFails("1974-12-25T23:59 00Z");
|
||||
|
||||
// Invalid length
|
||||
verifyFails("1974-12-25T2Z");
|
||||
verifyFails("1974-12-25T22:Z");
|
||||
verifyFails("1974-12-25T22:1Z");
|
||||
verifyFails("1974-12-25T22:11:Z");
|
||||
verifyFails("1974-12-25T22:11:1Z");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDateFormatsInvalid() {
|
||||
// No spaces in dates
|
||||
verifyFails("1974 12-25");
|
||||
verifyFails("1974-12 25");
|
||||
|
||||
// No letters
|
||||
verifyFails("A974-12-25");
|
||||
verifyFails("1974-A2-25");
|
||||
verifyFails("1974-12-A5");
|
||||
|
||||
// Date shouldn't have a time zone
|
||||
verifyFails("1974-12-25Z");
|
||||
verifyFails("1974-12-25+10:00");
|
||||
|
||||
// Out of range
|
||||
verifyFails("1974-13-25");
|
||||
verifyFails("1974-12-32");
|
||||
verifyFails("2015-02-29");
|
||||
verifyFails("-016-02-01");
|
||||
verifyFails("2016--2-01");
|
||||
verifyFails("2016-02--1");
|
||||
|
||||
// Invalid length
|
||||
verifyFails("2");
|
||||
verifyFails("20");
|
||||
verifyFails("201");
|
||||
verifyFails("2016-0");
|
||||
verifyFails("2016-02-0");
|
||||
}
|
||||
|
||||
|
||||
private void verifyFails(String input) {
|
||||
try {
|
||||
DateTimeDt dt = new DateTimeDt();
|
||||
dt.setValueAsString(input);
|
||||
fail();
|
||||
} catch (ca.uhn.fhir.parser.DataFormatException e) {
|
||||
assertThat(e.getMessage(), containsString("Invalid date/time format: \"" + input + "\""));
|
||||
}
|
||||
public void testParseIgnoresLeadingAndTrailingSpace() {
|
||||
DateTimeDt dt = new DateTimeDt(" 2014-10-11T12:11:00Z ");
|
||||
assertEquals("2014-10-11 10:11:00.000-0200", myDateInstantZoneParser.format(dt.getValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -328,17 +320,15 @@ public class BaseDateTimeDtDstu2Test {
|
|||
new DateTimeDt("2010-01-01T00:00:00.1234-09:00Z");
|
||||
fail();
|
||||
} catch (DataFormatException e) {
|
||||
assertEquals("Invalid FHIR date/time string: 2010-01-01T00:00:00.1234-09:00Z", e.getMessage());
|
||||
assertEquals("Invalid date/time format: \"2010-01-01T00:00:00.1234-09:00Z\"", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test(expected = DataFormatException.class)
|
||||
public void testParseMalformatted() throws DataFormatException {
|
||||
new DateTimeDt("20120102");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testParseMilli() throws DataFormatException {
|
||||
InstantDt dt = new InstantDt();
|
||||
|
@ -451,12 +441,12 @@ public class BaseDateTimeDtDstu2Test {
|
|||
DateTimeDt dt = new DateTimeDt("2010-01-01T00:00:00.1-09:00");
|
||||
|
||||
assertEquals("2010-01-01T00:00:00.1-09:00", dt.getValueAsString());
|
||||
assertEquals("2010-01-01 04:00:00.001", myDateInstantParser.format(dt.getValue()));
|
||||
assertEquals("2010-01-01 04:00:00.100", myDateInstantParser.format(dt.getValue()));
|
||||
assertEquals("GMT-09:00", dt.getTimeZone().getID());
|
||||
assertEquals(-32400000L, dt.getTimeZone().getRawOffset());
|
||||
|
||||
dt.setTimeZoneZulu(true);
|
||||
assertEquals("2010-01-01T09:00:00.001Z", dt.getValueAsString());
|
||||
assertEquals("2010-01-01T09:00:00.100Z", dt.getValueAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -466,12 +456,12 @@ public class BaseDateTimeDtDstu2Test {
|
|||
DateTimeDt dt = new DateTimeDt("2010-01-01T00:00:00.12-09:00");
|
||||
|
||||
assertEquals("2010-01-01T00:00:00.12-09:00", dt.getValueAsString());
|
||||
assertEquals("2010-01-01 04:00:00.012", myDateInstantParser.format(dt.getValue()));
|
||||
assertEquals("2010-01-01 04:00:00.120", myDateInstantParser.format(dt.getValue()));
|
||||
assertEquals("GMT-09:00", dt.getTimeZone().getID());
|
||||
assertEquals(-32400000L, dt.getTimeZone().getRawOffset());
|
||||
|
||||
dt.setTimeZoneZulu(true);
|
||||
assertEquals("2010-01-01T09:00:00.012Z", dt.getValueAsString());
|
||||
assertEquals("2010-01-01T09:00:00.120Z", dt.getValueAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -599,6 +589,24 @@ public class BaseDateTimeDtDstu2Test {
|
|||
assertThat(human, containsString("12"));
|
||||
}
|
||||
|
||||
private void validateMillisPartial(String input, int expected) {
|
||||
InstantDt dt = new InstantDt();
|
||||
dt.setValueAsString(input);
|
||||
Date date = dt.getValue();
|
||||
|
||||
assertEquals(expected, date.getTime() % 1000);
|
||||
}
|
||||
|
||||
private void verifyFails(String input) {
|
||||
try {
|
||||
DateTimeDt dt = new DateTimeDt();
|
||||
dt.setValueAsString(input);
|
||||
fail();
|
||||
} catch (ca.uhn.fhir.parser.DataFormatException e) {
|
||||
assertThat(e.getMessage(), containsString("Invalid date/time format: \"" + input + "\""));
|
||||
}
|
||||
}
|
||||
|
||||
public static void afterClass() {
|
||||
Locale.setDefault(ourDefaultLocale);
|
||||
}
|
||||
|
@ -611,8 +619,7 @@ public class BaseDateTimeDtDstu2Test {
|
|||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
/*
|
||||
* We cache the default locale, but temporarily set it to a random value during this test. This helps ensure
|
||||
* that there are no language specific dependencies in the test.
|
||||
* We cache the default locale, but temporarily set it to a random value during this test. This helps ensure that there are no language specific dependencies in the test.
|
||||
*/
|
||||
ourDefaultLocale = Locale.getDefault();
|
||||
|
||||
|
|
|
@ -16,33 +16,72 @@ import org.eclipse.jetty.server.Server;
|
|||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.rest.annotation.At;
|
||||
import ca.uhn.fhir.rest.annotation.History;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.Read;
|
||||
import ca.uhn.fhir.rest.annotation.Since;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
*/
|
||||
public class HistoryTest {
|
||||
public class HistoryDstu2Test {
|
||||
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static FhirContext ourCtx= FhirContext.forDstu1();
|
||||
private static FhirContext ourCtx = FhirContext.forDstu2();
|
||||
private static DateRangeParam ourLastAt;
|
||||
|
||||
private static InstantDt ourLastSince;
|
||||
private static int ourPort;
|
||||
|
||||
private static Server ourServer;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourLastAt = null;
|
||||
ourLastSince = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSince() throws Exception {
|
||||
{
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/_history?_since=2005");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertEquals(null, ourLastAt);
|
||||
assertEquals("2005", ourLastSince.getValueAsString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAt() throws Exception {
|
||||
{
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/_history?_at=gt2001&_at=lt2005");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertEquals(ParamPrefixEnum.GREATERTHAN, ourLastAt.getLowerBound().getPrefix());
|
||||
assertEquals("2001", ourLastAt.getLowerBound().getValueAsString());
|
||||
assertEquals(ParamPrefixEnum.LESSTHAN, ourLastAt.getUpperBound().getPrefix());
|
||||
assertEquals("2005", ourLastAt.getUpperBound().getValueAsString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstanceHistory() throws Exception {
|
||||
{
|
||||
|
@ -53,10 +92,10 @@ public class HistoryTest {
|
|||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
|
||||
assertEquals(2, bundle.getEntries().size());
|
||||
assertEquals("http://localhost:" + ourPort +"/Patient/ih1/_history/1", bundle.getEntries().get(0).getLinkSelf().getValue());
|
||||
assertEquals("http://localhost:" + ourPort +"/Patient/ih1/_history/2", bundle.getEntries().get(1).getLinkSelf().getValue());
|
||||
Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent);
|
||||
assertEquals(2, bundle.getEntry().size());
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/ih1/_history/1", bundle.getEntry().get(0).getResource().getId().getValue());
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/ih1/_history/2", bundle.getEntry().get(1).getResource().getId().getValue());
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -71,10 +110,10 @@ public class HistoryTest {
|
|||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
|
||||
assertEquals(2, bundle.getEntries().size());
|
||||
assertEquals("http://localhost:" + ourPort +"/Patient/h1/_history/1", bundle.getEntries().get(0).getLinkSelf().getValue());
|
||||
assertEquals("http://localhost:" + ourPort +"/Patient/h1/_history/2", bundle.getEntries().get(1).getLinkSelf().getValue());
|
||||
Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent);
|
||||
assertEquals(2, bundle.getEntry().size());
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/h1/_history/1", bundle.getEntry().get(0).getResource().getId().getValue());
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/h1/_history/2", bundle.getEntry().get(1).getResource().getId().getValue());
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -89,10 +128,12 @@ public class HistoryTest {
|
|||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
|
||||
assertEquals(2, bundle.getEntries().size());
|
||||
assertEquals("http://localhost:" + ourPort +"/Patient/th1/_history/1", bundle.getEntries().get(0).getLinkSelf().getValue());
|
||||
assertEquals("http://localhost:" + ourPort +"/Patient/th1/_history/2", bundle.getEntries().get(1).getLinkSelf().getValue());
|
||||
assertNull(ourLastAt);
|
||||
|
||||
Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent);
|
||||
assertEquals(2, bundle.getEntry().size());
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/th1/_history/1", bundle.getEntry().get(0).getResource().getId().getValue());
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/th1/_history/2", bundle.getEntry().get(1).getResource().getId().getValue());
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -145,38 +186,34 @@ public class HistoryTest {
|
|||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
*/
|
||||
public static class DummyPlainProvider {
|
||||
|
||||
@History
|
||||
public List<Patient> history(@Since InstantDt theSince) {
|
||||
public List<Patient> history(@Since InstantDt theSince, @At DateRangeParam theAt) {
|
||||
ourLastAt = theAt;
|
||||
ourLastSince = theSince;
|
||||
|
||||
ArrayList<Patient> retVal = new ArrayList<Patient>();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.setId("Patient/h1/_history/1");
|
||||
patient.addName().addFamily("history");
|
||||
retVal.add(patient);
|
||||
Patient patient = new Patient();
|
||||
patient.setId("Patient/h1/_history/1");
|
||||
patient.addName().addFamily("history");
|
||||
retVal.add(patient);
|
||||
|
||||
Patient patient2 = new Patient();
|
||||
patient2.setId("Patient/h1/_history/2");
|
||||
patient2.addName().addFamily("history");
|
||||
retVal.add(patient2);
|
||||
Patient patient2 = new Patient();
|
||||
patient2.setId("Patient/h1/_history/2");
|
||||
patient2.addName().addFamily("history");
|
||||
retVal.add(patient2);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static class DummyResourceProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<? extends IResource> getResourceType() {
|
||||
public Class<? extends Patient> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
|
@ -184,15 +221,15 @@ public class HistoryTest {
|
|||
public List<Patient> instanceHistory(@IdParam IdDt theId) {
|
||||
ArrayList<Patient> retVal = new ArrayList<Patient>();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.setId("Patient/ih1/_history/1");
|
||||
patient.addName().addFamily("history");
|
||||
retVal.add(patient);
|
||||
Patient patient = new Patient();
|
||||
patient.setId("Patient/ih1/_history/1");
|
||||
patient.addName().addFamily("history");
|
||||
retVal.add(patient);
|
||||
|
||||
Patient patient2 = new Patient();
|
||||
patient2.setId("Patient/ih1/_history/2");
|
||||
patient2.addName().addFamily("history");
|
||||
retVal.add(patient2);
|
||||
Patient patient2 = new Patient();
|
||||
patient2.setId("Patient/ih1/_history/2");
|
||||
patient2.addName().addFamily("history");
|
||||
retVal.add(patient2);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
@ -201,20 +238,20 @@ public class HistoryTest {
|
|||
public List<Patient> typeHistory() {
|
||||
ArrayList<Patient> retVal = new ArrayList<Patient>();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.setId("Patient/th1/_history/1");
|
||||
patient.addName().addFamily("history");
|
||||
retVal.add(patient);
|
||||
Patient patient = new Patient();
|
||||
patient.setId("Patient/th1/_history/1");
|
||||
patient.addName().addFamily("history");
|
||||
retVal.add(patient);
|
||||
|
||||
Patient patient2 = new Patient();
|
||||
patient2.setId("Patient/th1/_history/2");
|
||||
patient2.addName().addFamily("history");
|
||||
retVal.add(patient2);
|
||||
Patient patient2 = new Patient();
|
||||
patient2.setId("Patient/th1/_history/2");
|
||||
patient2.addName().addFamily("history");
|
||||
retVal.add(patient2);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Read(version=true)
|
||||
@Read(version = true)
|
||||
public Patient vread(@IdParam IdDt theId) {
|
||||
Patient retVal = new Patient();
|
||||
retVal.addName().addFamily("vread");
|
||||
|
@ -222,8 +259,6 @@ public class HistoryTest {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -52,14 +52,14 @@ public class OperationDuplicateServerDstu2Test {
|
|||
ourLog.info(response);
|
||||
|
||||
Conformance resp = ourCtx.newXmlParser().parseResource(Conformance.class, response);
|
||||
assertEquals(1, resp.getRest().get(0).getOperation().size());
|
||||
assertEquals("$myoperation", resp.getRest().get(0).getOperation().get(0).getName());
|
||||
assertEquals("OperationDefinition/myoperation", resp.getRest().get(0).getOperation().get(0).getDefinition().getReference().getValue());
|
||||
assertEquals(3, resp.getRest().get(0).getOperation().size());
|
||||
assertEquals("myoperation", resp.getRest().get(0).getOperation().get(0).getName());
|
||||
assertEquals("OperationDefinition/-s-myoperation", resp.getRest().get(0).getOperation().get(0).getDefinition().getReference().getValue());
|
||||
}
|
||||
|
||||
// OperationDefinition
|
||||
{
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/OperationDefinition/myoperation?_pretty=true");
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/OperationDefinition/-s-myoperation?_pretty=true");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
@ -69,10 +69,27 @@ public class OperationDuplicateServerDstu2Test {
|
|||
|
||||
OperationDefinition resp = ourCtx.newXmlParser().parseResource(OperationDefinition.class, response);
|
||||
assertEquals(true, resp.getSystemElement().getValue().booleanValue());
|
||||
assertEquals("$myoperation", resp.getCode());
|
||||
assertEquals("myoperation", resp.getCode());
|
||||
assertEquals(true, resp.getIdempotent().booleanValue());
|
||||
assertEquals(2, resp.getType().size());
|
||||
assertThat(Arrays.asList(resp.getType().get(0).getValue(), resp.getType().get(1).getValue()), containsInAnyOrder("Organization", "Patient"));
|
||||
assertEquals(0, resp.getType().size());
|
||||
assertEquals(1, resp.getParameter().size());
|
||||
}
|
||||
// OperationDefinition
|
||||
{
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/OperationDefinition/Organization--myoperation?_pretty=true");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(response);
|
||||
|
||||
OperationDefinition resp = ourCtx.newXmlParser().parseResource(OperationDefinition.class, response);
|
||||
assertEquals(false, resp.getSystemElement().getValue().booleanValue());
|
||||
assertEquals("myoperation", resp.getCode());
|
||||
assertEquals(true, resp.getIdempotent().booleanValue());
|
||||
assertEquals(1, resp.getType().size());
|
||||
assertEquals("Organization", resp.getType().get(0).getValue());
|
||||
assertEquals(1, resp.getParameter().size());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ public class OperationServerDstu2Test {
|
|||
List<String> opNames = toOpNames(ops);
|
||||
assertThat(opNames, containsInRelativeOrder("OP_TYPE"));
|
||||
|
||||
assertEquals("OperationDefinition/OP_TYPE", ops.get(opNames.indexOf("OP_TYPE")).getDefinition().getReference().getValue());
|
||||
assertEquals("OperationDefinition/Patient--OP_TYPE", ops.get(opNames.indexOf("OP_TYPE")).getDefinition().getReference().getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -112,7 +112,7 @@ public class OperationServerDstu2Test {
|
|||
*/
|
||||
@Test
|
||||
public void testOperationDefinition() {
|
||||
OperationDefinition def = myFhirClient.read().resource(OperationDefinition.class).withId("OperationDefinition/OP_TYPE").execute();
|
||||
OperationDefinition def = myFhirClient.read().resource(OperationDefinition.class).withId("OperationDefinition/Patient--OP_TYPE").execute();
|
||||
|
||||
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(def));
|
||||
|
||||
|
|
|
@ -181,7 +181,7 @@ public class OperationServerWithSearchParamTypesDstu2Test {
|
|||
/*
|
||||
* Check the operation definitions themselves
|
||||
*/
|
||||
OperationDefinition andListDef = sc.readOperationDefinition(new IdDt("OperationDefinition/andlist"));
|
||||
OperationDefinition andListDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient--andlist"));
|
||||
String def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(andListDef);
|
||||
ourLog.info(def);
|
||||
//@formatter:off
|
||||
|
|
|
@ -171,7 +171,7 @@ public class ServerConformanceProviderDstu2Test {
|
|||
|
||||
assertEquals(1, conformance.getRest().get(0).getOperation().size());
|
||||
assertEquals("everything", conformance.getRest().get(0).getOperation().get(0).getName());
|
||||
assertEquals("OperationDefinition/Patient_i_everything", conformance.getRest().get(0).getOperation().get(0).getDefinition().getReference().getValue());
|
||||
assertEquals("OperationDefinition/Patient-i-everything", conformance.getRest().get(0).getOperation().get(0).getDefinition().getReference().getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -186,7 +186,7 @@ public class ServerConformanceProviderDstu2Test {
|
|||
|
||||
rs.init(createServletConfig());
|
||||
|
||||
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient_i_everything"));
|
||||
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient-i-everything"));
|
||||
validate(opDef);
|
||||
|
||||
assertEquals("everything", opDef.getCode());
|
||||
|
@ -290,10 +290,10 @@ public class ServerConformanceProviderDstu2Test {
|
|||
assertThat(operationNames, containsInAnyOrder("someOp", "validate", "someOp", "validate"));
|
||||
|
||||
List<String> operationIdParts = toOperationIdParts(conformance.getRest().get(0).getOperation());
|
||||
assertThat(operationIdParts, containsInAnyOrder("Patient_i_someOp","Encounter_i_someOp","Patient_i_validate","Encounter_i_validate"));
|
||||
assertThat(operationIdParts, containsInAnyOrder("Patient-i-someOp","Encounter-i-someOp","Patient-i-validate","Encounter-i-validate"));
|
||||
|
||||
{
|
||||
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient_i_someOp"));
|
||||
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient-i-someOp"));
|
||||
validate(opDef);
|
||||
|
||||
Set<String> types = toStrings(opDef.getType());
|
||||
|
@ -308,7 +308,7 @@ public class ServerConformanceProviderDstu2Test {
|
|||
assertEquals("Patient", opDef.getParameter().get(1).getType());
|
||||
}
|
||||
{
|
||||
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Encounter_i_someOp"));
|
||||
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Encounter-i-someOp"));
|
||||
validate(opDef);
|
||||
|
||||
Set<String> types = toStrings(opDef.getType());
|
||||
|
@ -323,7 +323,7 @@ public class ServerConformanceProviderDstu2Test {
|
|||
assertEquals("Encounter", opDef.getParameter().get(1).getType());
|
||||
}
|
||||
{
|
||||
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient_i_validate"));
|
||||
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient-i-validate"));
|
||||
validate(opDef);
|
||||
|
||||
Set<String> types = toStrings(opDef.getType());
|
||||
|
@ -374,9 +374,9 @@ public class ServerConformanceProviderDstu2Test {
|
|||
rs.init(createServletConfig());
|
||||
|
||||
Conformance sconf = sc.getServerConformance(createHttpServletRequest());
|
||||
assertEquals("OperationDefinition/_is_plain", sconf.getRest().get(0).getOperation().get(0).getDefinition().getReference().getValue());
|
||||
assertEquals("OperationDefinition/-is-plain", sconf.getRest().get(0).getOperation().get(0).getDefinition().getReference().getValue());
|
||||
|
||||
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/_is_plain"));
|
||||
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/-is-plain"));
|
||||
validate(opDef);
|
||||
|
||||
assertEquals("plain", opDef.getCode());
|
||||
|
|
|
@ -41,10 +41,6 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.dstu3.exceptions.FHIRException;
|
||||
import org.hl7.fhir.dstu3.model.Conformance;
|
||||
import org.hl7.fhir.dstu3.model.DateTimeType;
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.dstu3.model.OperationDefinition;
|
||||
import org.hl7.fhir.dstu3.model.ResourceType;
|
||||
import org.hl7.fhir.dstu3.model.Conformance.ConditionalDeleteStatus;
|
||||
import org.hl7.fhir.dstu3.model.Conformance.ConformanceRestComponent;
|
||||
import org.hl7.fhir.dstu3.model.Conformance.ConformanceRestResourceComponent;
|
||||
|
@ -55,11 +51,15 @@ import org.hl7.fhir.dstu3.model.Conformance.RestfulConformanceMode;
|
|||
import org.hl7.fhir.dstu3.model.Conformance.SystemRestfulInteraction;
|
||||
import org.hl7.fhir.dstu3.model.Conformance.TypeRestfulInteraction;
|
||||
import org.hl7.fhir.dstu3.model.Conformance.UnknownContentCode;
|
||||
import org.hl7.fhir.dstu3.model.DateTimeType;
|
||||
import org.hl7.fhir.dstu3.model.Enumerations.ConformanceResourceStatus;
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.dstu3.model.OperationDefinition;
|
||||
import org.hl7.fhir.dstu3.model.OperationDefinition.OperationDefinitionParameterComponent;
|
||||
import org.hl7.fhir.dstu3.model.OperationDefinition.OperationKind;
|
||||
import org.hl7.fhir.dstu3.model.OperationDefinition.OperationParameterUse;
|
||||
import org.hl7.fhir.dstu3.model.Reference;
|
||||
import org.hl7.fhir.dstu3.model.ResourceType;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
|
@ -79,7 +79,6 @@ import ca.uhn.fhir.rest.method.OperationParameter;
|
|||
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
|
||||
import ca.uhn.fhir.rest.method.SearchMethodBinding;
|
||||
import ca.uhn.fhir.rest.method.SearchParameter;
|
||||
import ca.uhn.fhir.rest.method.ValidateMethodBindingDstu3;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.IServerConformanceProvider;
|
||||
import ca.uhn.fhir.rest.server.ResourceBinding;
|
||||
|
@ -181,14 +180,14 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
|||
retVal.append(theMethodBinding.getResourceName());
|
||||
}
|
||||
|
||||
retVal.append('_');
|
||||
retVal.append('-');
|
||||
if (theMethodBinding.isCanOperateAtInstanceLevel()) {
|
||||
retVal.append('i');
|
||||
}
|
||||
if (theMethodBinding.isCanOperateAtServerLevel()) {
|
||||
retVal.append('s');
|
||||
}
|
||||
retVal.append('_');
|
||||
retVal.append('-');
|
||||
|
||||
// Exclude the leading $
|
||||
retVal.append(theMethodBinding.getName(), 1, theMethodBinding.getName().length());
|
||||
|
@ -344,7 +343,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
|||
String opName = myOperationBindingToName.get(methodBinding);
|
||||
if (operationNames.add(opName)) {
|
||||
ourLog.info("Found bound operation: {}", opName);
|
||||
rest.addOperation().setName(opName).setDefinition(new Reference("OperationDefinition/" + opName));
|
||||
rest.addOperation().setName(methodBinding.getName().substring(1)).setDefinition(new Reference("OperationDefinition/" + opName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,11 @@ import static org.mockito.Mockito.when;
|
|||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.apache.commons.io.input.ReaderInputStream;
|
||||
import org.apache.http.HttpResponse;
|
||||
|
@ -21,6 +25,7 @@ import org.hl7.fhir.dstu3.model.Bundle;
|
|||
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.dstu3.model.Extension;
|
||||
import org.hl7.fhir.dstu3.model.Location;
|
||||
import org.hl7.fhir.dstu3.model.StringType;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@ -31,16 +36,18 @@ import org.mockito.stubbing.Answer;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.annotation.Count;
|
||||
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
||||
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.annotation.Sort;
|
||||
import ca.uhn.fhir.rest.api.SortOrderEnum;
|
||||
import ca.uhn.fhir.rest.api.SortSpec;
|
||||
import ca.uhn.fhir.rest.client.api.IRestfulClient;
|
||||
import ca.uhn.fhir.rest.param.DateParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
|
||||
public class SearchClientDstu3Test {
|
||||
|
||||
|
@ -54,7 +61,6 @@ public class SearchClientDstu3Test {
|
|||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourCtx = FhirContext.forDstu3();
|
||||
|
@ -123,6 +129,45 @@ public class SearchClientDstu3Test {
|
|||
assertEquals("http://localhost/fhir/Bundle?_sort=param1%2C-param2", ((HttpGet) capt.getAllValues().get(idx++)).getURI().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithPrimitiveTypes() throws Exception {
|
||||
TimeZone tz = TimeZone.getDefault();
|
||||
try {
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("America/Toronto"));
|
||||
|
||||
Date date = new Date(23898235986L);
|
||||
Calendar cal = new GregorianCalendar();
|
||||
cal.setTime(date);
|
||||
;
|
||||
|
||||
final String response = createBundleWithSearchExtension();
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(ourHttpClient.execute(capt.capture())).thenReturn(ourHttpResponse);
|
||||
when(ourHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(ourHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(ourHttpResponse.getEntity().getContent()).thenAnswer(new Answer<InputStream>() {
|
||||
@Override
|
||||
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
return new ReaderInputStream(new StringReader(response), Charset.forName("UTF-8"));
|
||||
}
|
||||
});
|
||||
|
||||
ILocationClient client = ourCtx.newRestfulClient(ILocationClient.class, "http://localhost/fhir");
|
||||
|
||||
int idx = 0;
|
||||
|
||||
client.search("STRING1", new StringType("STRING2"), date, cal);
|
||||
assertEquals("http://localhost/fhir/Bundle?stringParam=STRING1&stringTypeParam=STRING2&dateParam=1970-10-04T10:23:55.986-04:00&calParam=1970-10-04T10:23:55.986-04:00",
|
||||
UrlUtil.unescape(((HttpGet) capt.getAllValues().get(idx++)).getURI().toString()));
|
||||
|
||||
client.search(null, null, null, null);
|
||||
assertEquals("http://localhost/fhir/Bundle",
|
||||
UrlUtil.unescape(((HttpGet) capt.getAllValues().get(idx++)).getURI().toString()));
|
||||
} finally {
|
||||
TimeZone.setDefault(tz);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See #299
|
||||
*/
|
||||
|
@ -147,7 +192,7 @@ public class SearchClientDstu3Test {
|
|||
|
||||
assertEquals(1, matches.getEntry().size());
|
||||
BundleEntryComponent entry = matches.getEntry().get(0);
|
||||
assertEquals("Sample Clinic", ((Location)entry.getResource()).getName());
|
||||
assertEquals("Sample Clinic", ((Location) entry.getResource()).getName());
|
||||
|
||||
List<Extension> ext = entry.getSearch().getExtensionsByUrl("http://hl7.org/fhir/StructureDefinition/algorithmic-match");
|
||||
assertEquals(1, ext.size());
|
||||
|
@ -183,17 +228,20 @@ public class SearchClientDstu3Test {
|
|||
return response;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public interface ILocationClient extends IRestfulClient {
|
||||
@Search(queryName = "match")
|
||||
public List<Location> getMatches(final @RequiredParam(name = Location.SP_NAME) StringParam name, final @Count Integer count);
|
||||
|
||||
@Search(queryName = "match", type=Location.class)
|
||||
@Search(queryName = "match", type = Location.class)
|
||||
public Bundle getMatchesReturnBundle(final @RequiredParam(name = Location.SP_NAME) StringParam name, final @Count Integer count);
|
||||
|
||||
@Search
|
||||
public Bundle search(@Sort SortSpec theSort);
|
||||
|
||||
@Search
|
||||
public Bundle search(@OptionalParam(name = "stringParam") String theString, @OptionalParam(name = "stringTypeParam") StringType theStringDt, @OptionalParam(name = "dateParam") Date theDate,
|
||||
@OptionalParam(name = "calParam") Calendar theCal);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -91,6 +91,8 @@ public class OperationServerDstu3Test {
|
|||
myFhirClient.registerInterceptor(loggingInterceptor);
|
||||
|
||||
Conformance p = myFhirClient.fetchConformance().ofType(Conformance.class).prettyPrint().execute();
|
||||
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p));
|
||||
|
||||
List<ConformanceRestOperationComponent> ops = p.getRest().get(0).getOperation();
|
||||
assertThat(ops.size(), greaterThan(1));
|
||||
|
||||
|
@ -107,7 +109,7 @@ public class OperationServerDstu3Test {
|
|||
*/
|
||||
@Test
|
||||
public void testOperationDefinition() {
|
||||
OperationDefinition def = myFhirClient.read().resource(OperationDefinition.class).withId("OperationDefinition/OP_TYPE").execute();
|
||||
OperationDefinition def = myFhirClient.read().resource(OperationDefinition.class).withId("OperationDefinition/Patient--OP_TYPE").execute();
|
||||
|
||||
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(def));
|
||||
|
||||
|
|
|
@ -192,7 +192,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
|
|||
/*
|
||||
* Check the operation definitions themselves
|
||||
*/
|
||||
OperationDefinition andListDef = sc.readOperationDefinition(new IdType("OperationDefinition/andlist"));
|
||||
OperationDefinition andListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--andlist"));
|
||||
String def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(andListDef);
|
||||
ourLog.info(def);
|
||||
//@formatter:off
|
||||
|
@ -208,7 +208,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
|
|||
));
|
||||
//@formatter:on
|
||||
|
||||
andListDef = sc.readOperationDefinition(new IdType("OperationDefinition/andlist-withnomax"));
|
||||
andListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--andlist-withnomax"));
|
||||
def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(andListDef);
|
||||
ourLog.info(def);
|
||||
//@formatter:off
|
||||
|
@ -224,7 +224,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
|
|||
));
|
||||
//@formatter:on
|
||||
|
||||
OperationDefinition orListDef = sc.readOperationDefinition(new IdType("OperationDefinition/orlist"));
|
||||
OperationDefinition orListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--orlist"));
|
||||
def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(orListDef);
|
||||
ourLog.info(def);
|
||||
//@formatter:off
|
||||
|
@ -240,7 +240,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
|
|||
));
|
||||
//@formatter:on
|
||||
|
||||
orListDef = sc.readOperationDefinition(new IdType("OperationDefinition/orlist-withnomax"));
|
||||
orListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--orlist-withnomax"));
|
||||
def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(orListDef);
|
||||
ourLog.info(def);
|
||||
//@formatter:off
|
||||
|
|
|
@ -159,7 +159,7 @@ public class ServerConformanceProviderDstu3Test {
|
|||
assertEquals(1, conformance.getRest().get(0).getOperation().size());
|
||||
assertEquals("everything", conformance.getRest().get(0).getOperation().get(0).getName());
|
||||
|
||||
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient_i_everything"));
|
||||
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-everything"));
|
||||
validate(opDef);
|
||||
assertEquals("everything", opDef.getCode());
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ public class ServerConformanceProviderDstu3Test {
|
|||
|
||||
rs.init(createServletConfig());
|
||||
|
||||
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient_i_everything"));
|
||||
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-everything"));
|
||||
validate(opDef);
|
||||
|
||||
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef);
|
||||
|
@ -282,10 +282,10 @@ public class ServerConformanceProviderDstu3Test {
|
|||
assertThat(operationNames, containsInAnyOrder("someOp", "validate", "someOp", "validate"));
|
||||
|
||||
List<String> operationIdParts = toOperationIdParts(conformance.getRest().get(0).getOperation());
|
||||
assertThat(operationIdParts, containsInAnyOrder("Patient_i_someOp", "Encounter_i_someOp", "Patient_i_validate", "Encounter_i_validate"));
|
||||
assertThat(operationIdParts, containsInAnyOrder("Patient-i-someOp", "Encounter-i-someOp", "Patient-i-validate", "Encounter-i-validate"));
|
||||
|
||||
{
|
||||
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient_i_someOp"));
|
||||
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-someOp"));
|
||||
validate(opDef);
|
||||
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef));
|
||||
Set<String> types = toStrings(opDef.getType());
|
||||
|
@ -300,7 +300,7 @@ public class ServerConformanceProviderDstu3Test {
|
|||
assertEquals("Patient", opDef.getParameter().get(1).getType());
|
||||
}
|
||||
{
|
||||
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Encounter_i_someOp"));
|
||||
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Encounter-i-someOp"));
|
||||
validate(opDef);
|
||||
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef));
|
||||
Set<String> types = toStrings(opDef.getType());
|
||||
|
@ -315,7 +315,7 @@ public class ServerConformanceProviderDstu3Test {
|
|||
assertEquals("Encounter", opDef.getParameter().get(1).getType());
|
||||
}
|
||||
{
|
||||
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient_i_validate"));
|
||||
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-validate"));
|
||||
validate(opDef);
|
||||
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef));
|
||||
Set<String> types = toStrings(opDef.getType());
|
||||
|
@ -364,7 +364,7 @@ public class ServerConformanceProviderDstu3Test {
|
|||
|
||||
rs.init(createServletConfig());
|
||||
|
||||
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/_is_plain"));
|
||||
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/-is-plain"));
|
||||
validate(opDef);
|
||||
|
||||
assertEquals("plain", opDef.getCode());
|
||||
|
|
|
@ -344,6 +344,21 @@
|
|||
<![CDATA[@OperationParam]]> annotation describes. Thanks to Michael Lawley
|
||||
for reporting!
|
||||
</action>
|
||||
<action type="fix">
|
||||
Server parameters annotated with
|
||||
<![CDATA[<code>@Since</code>]]>
|
||||
or
|
||||
<![CDATA[<code>@CountS</code>]]>
|
||||
which are of a FHIR type such as IntegerDt or DateTimeType will
|
||||
now be set to null if the client's URL does not
|
||||
contain this parameter. Previously they would be populated
|
||||
with an empty instance of the FHIR type, which was inconsistent with
|
||||
the way other server parameters worked.
|
||||
</action>
|
||||
<action type="add">
|
||||
Server now supports the _at parameter (including multiple repetitions)
|
||||
for history operation
|
||||
</action>
|
||||
</release>
|
||||
<release version="1.5" date="2016-04-20">
|
||||
<action type="fix" issue="339">
|
||||
|
|
|
@ -1379,8 +1379,22 @@
|
|||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
The following snippet shows how to define a history method on a server:
|
||||
The following snippet shows how to define a history method on a server. Note that
|
||||
the following parameters are both optional, but may be useful in
|
||||
implementing the history operation:
|
||||
</p>
|
||||
<u>
|
||||
<li>
|
||||
The <code>@Since</code> method argument implements the <code>_since</code>
|
||||
parameter and should be of type <code>DateTimeDt</code> or <code>DateTimeType</code>
|
||||
</li>
|
||||
<li>
|
||||
The <code>@At</code> method argument implements the <code>_at</code>
|
||||
parameter and may be of type
|
||||
<code>DateRangeParam</code>,
|
||||
<code>DateTimeDt</code> or <code>DateTimeType</code>
|
||||
</li>
|
||||
</u>
|
||||
|
||||
<macro name="snippet">
|
||||
<param name="id" value="history" />
|
||||
|
|
Loading…
Reference in New Issue