Merge remote-tracking branch 'remotes/origin/master' into ks-flyway

# Conflicts:
#	src/changes/changes.xml
This commit is contained in:
Ken Stevens 2019-11-24 16:42:23 -05:00
commit a32c62f83b
49 changed files with 872 additions and 308 deletions

View File

@ -13,19 +13,22 @@ pool:
jobs:
- job: Build
timeoutInMinutes: 360
container: maven:3-jdk-11
steps:
- task: CacheBeta@0
inputs:
key: maven
path: $(MAVEN_CACHE_FOLDER)
displayName: Cache Maven local repo
- task: Maven@3
env:
JAVA_HOME_11_X64: /usr/local/openjdk-11
inputs:
goals: 'clean install'
# These are Maven CLI options (and show up in the build logs) - "-nsu"=Don't update snapshots. We can remove this when Maven OSS is more healthy
options: '-P ALLMODULES,JACOCO -nsu'
options: '-P ALLMODULES,JACOCO,CI -nsu'
# These are JVM options (and don't show up in the build logs)
mavenOptions: '-Xmx2048m $(MAVEN_OPTS) -Dorg.slf4j.simpleLogger.showDateTime=true -Dorg.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss,SSS -Duser.timezone=America/Toronto'
jdkVersionOption: 1.11
- script: bash <(curl https://codecov.io/bash) -t $(CODECOV_TOKEN)
displayName: 'codecov'
- task: PublishCodeCoverageResults@1

View File

@ -145,7 +145,7 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>@{argLine} -Dfile.encoding=UTF-8 -Xmx712m</argLine>
<argLine>@{argLine} ${surefire_jvm_args}</argLine>
</configuration>
</plugin>
<plugin>

View File

@ -20,6 +20,12 @@ package ca.uhn.fhir.context;
* #L%
*/
import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.api.IDatatype;
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
import org.apache.commons.text.WordUtils;
import org.hl7.fhir.instance.model.api.IBase;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@ -27,18 +33,11 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.text.WordUtils;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.api.IDatatype;
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildDefinition {
private static final String VALUE_REFERENCE = "valueReference";
private static final String VALUE_RESOURCE = "valueResource";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RuntimeChildUndeclaredExtensionDefinition.class);
private Map<String, BaseRuntimeElementDefinition<?>> myAttributeNameToDefinition;
private Map<Class<? extends IBase>, String> myDatatypeToAttributeName;
private Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> myDatatypeToDefinition;
@ -48,15 +47,13 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
}
private void addReferenceBinding(FhirContext theContext, Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions, String value) {
List<Class<? extends IBaseResource>> types = new ArrayList<Class<? extends IBaseResource>>();
types.add(IBaseResource.class);
BaseRuntimeElementDefinition<?> def = findResourceReferenceDefinition(theClassToElementDefinitions);
myAttributeNameToDefinition.put(value, def);
/*
* Resource reference - The correct name is 'valueReference' in DSTU2 and 'valueResource' in DSTU1
*/
if (value != VALUE_RESOURCE) {
if (!value.equals(VALUE_RESOURCE)) {
myDatatypeToAttributeName.put(theContext.getVersion().getResourceReferenceType(), value);
myDatatypeToDefinition.put(BaseResourceReferenceDt.class, def);
myDatatypeToDefinition.put(theContext.getVersion().getResourceReferenceType(), def);
@ -71,10 +68,9 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
public List<IBase> getValues(IBase theTarget) {
ExtensionDt target = (ExtensionDt) theTarget;
if (target.getValue() != null) {
return Collections.singletonList((IBase) target.getValue());
return Collections.singletonList(target.getValue());
}
ArrayList<IBase> retVal = new ArrayList<IBase>(target.getUndeclaredExtensions());
return retVal;
return new ArrayList<>(target.getUndeclaredExtensions());
}
};
@ -116,22 +112,13 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
@Override
public void addValue(IBase theTarget, IBase theValue) {
ExtensionDt target = (ExtensionDt) theTarget;
if (theValue instanceof IDatatype) {
target.setValue((IDatatype) theTarget);
} else {
target.getUndeclaredExtensions().add((ExtensionDt) theValue);
}
target.setValue((IDatatype) theTarget);
}
@Override
public void setValue(IBase theTarget, IBase theValue) {
ExtensionDt target = (ExtensionDt) theTarget;
if (theValue instanceof IDatatype) {
target.setValue((IDatatype) theTarget);
} else {
target.getUndeclaredExtensions().clear();
target.getUndeclaredExtensions().add((ExtensionDt) theValue);
}
target.setValue((IDatatype) theTarget);
}
};
}
@ -146,8 +133,6 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
return false;
}
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RuntimeChildUndeclaredExtensionDefinition.class);
@Override
void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
Map<String, BaseRuntimeElementDefinition<?>> datatypeAttributeNameToDefinition = new HashMap<>();
@ -163,15 +148,15 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
if (isSpecialization) {
ourLog.trace("Not adding specialization: {}", next.getImplementingClass());
}
if (!isSpecialization) {
if (!next.isStandardType()) {
continue;
}
String qualifiedName = next.getImplementingClass().getName();
/*
* We don't want user-defined custom datatypes ending up overriding the built in
* types here. It would probably be better for there to be a way for
@ -183,7 +168,7 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
continue;
}
}
String attrName = createExtensionChildName(next);
if (datatypeAttributeNameToDefinition.containsKey(attrName)) {
BaseRuntimeElementDefinition<?> existing = datatypeAttributeNameToDefinition.get(attrName);
@ -207,8 +192,7 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
}
public static String createExtensionChildName(BaseRuntimeElementDefinition<?> next) {
String attrName = "value" + WordUtils.capitalize(next.getName());
return attrName;
return "value" + WordUtils.capitalize(next.getName());
}
}

View File

@ -22,10 +22,16 @@ package ca.uhn.fhir.parser;
import ca.uhn.fhir.context.*;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum;
import ca.uhn.fhir.model.api.*;
import ca.uhn.fhir.model.api.IIdentifiableElement;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions;
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.primitive.IdDt;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.util.BundleUtil;
import ca.uhn.fhir.util.UrlUtil;
import com.google.common.base.Charsets;
import org.apache.commons.lang3.StringUtils;
@ -35,7 +41,13 @@ import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.hl7.fhir.instance.model.api.*;
import javax.annotation.Nullable;
import java.io.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;
@ -530,11 +542,6 @@ public abstract class BaseParser implements IParser {
return tags;
}
@Override
public Boolean getOverrideResourceIdWithBundleEntryFullUrl() {
return myOverrideResourceIdWithBundleEntryFullUrl;
}
@Override
public List<Class<? extends IBaseResource>> getPreferTypes() {
return myPreferTypes;
@ -705,39 +712,38 @@ public abstract class BaseParser implements IParser {
RuntimeResourceDefinition def = myContext.getResourceDefinition(retVal);
if ("Bundle".equals(def.getName())) {
BaseRuntimeChildDefinition entryChild = def.getChildByName("entry");
BaseRuntimeElementCompositeDefinition<?> entryDef = (BaseRuntimeElementCompositeDefinition<?>) entryChild.getChildByName("entry");
List<IBase> entries = entryChild.getAccessor().getValues(retVal);
if (entries != null) {
for (IBase nextEntry : entries) {
/**
* If Bundle.entry.fullUrl is populated, set the resource ID to that
*/
// TODO: should emit a warning and maybe notify the error handler if the resource ID doesn't match the
// fullUrl idPart
BaseRuntimeChildDefinition fullUrlChild = entryDef.getChildByName("fullUrl");
if (fullUrlChild == null) {
continue; // TODO: remove this once the data model in tinder plugin catches up to 1.2
}
if (isOverrideResourceIdWithBundleEntryFullUrl()) {
List<IBase> fullUrl = fullUrlChild.getAccessor().getValues(nextEntry);
if (fullUrl != null && !fullUrl.isEmpty()) {
IPrimitiveType<?> value = (IPrimitiveType<?>) fullUrl.get(0);
if (value.isEmpty() == false) {
List<IBase> entryResources = entryDef.getChildByName("resource").getAccessor().getValues(nextEntry);
if (entryResources != null && entryResources.size() > 0) {
IBaseResource res = (IBaseResource) entryResources.get(0);
String versionId = res.getIdElement().getVersionIdPart();
res.setId(value.getValueAsString());
if (isNotBlank(versionId) && res.getIdElement().hasVersionIdPart() == false) {
res.setId(res.getIdElement().withVersion(versionId));
if (isOverrideResourceIdWithBundleEntryFullUrl()) {
BundleUtil.processEntries(myContext, (IBaseBundle) retVal, t -> {
String fullUrl = t.getFullUrl();
if (fullUrl != null) {
IBaseResource resource = t.getResource();
if (resource != null) {
IIdType resourceId = resource.getIdElement();
if (isBlank(resourceId.getValue())) {
resourceId.setValue(fullUrl);
} else {
if (fullUrl.startsWith("urn:") && fullUrl.endsWith(":" + resourceId.getIdPart())) {
resourceId.setValue(fullUrl);
} else {
IIdType fullUrlId = myContext.getVersion().newIdType();
fullUrlId.setValue(fullUrl);
if (myContext.getVersion().getVersion().isOlderThan(FhirVersionEnum.DSTU3)) {
IIdType newId = fullUrlId;
if (!newId.hasVersionIdPart() && resourceId.hasVersionIdPart()) {
newId = newId.withVersion(resourceId.getVersionIdPart());
}
resourceId.setValue(newId.getValue());
} else if (StringUtils.equals(fullUrlId.getIdPart(), resourceId.getIdPart())) {
if (fullUrlId.hasBaseUrl()) {
IIdType newResourceId = resourceId.withServerBase(fullUrlId.getBaseUrl(), resourceId.getResourceType());
resourceId.setValue(newResourceId.getValue());
}
}
}
}
}
}
}
});
}
}

View File

@ -92,19 +92,6 @@ public interface IParser {
*/
Boolean getStripVersionsFromReferences();
/**
* If set to <code>true</code> (which is the default), the Bundle.entry.fullUrl will override the Bundle.entry.resource's
* resource id if the fullUrl is defined. This behavior happens when parsing the source data into a Bundle object. Set this
* to <code>false</code> if this is not the desired behavior (e.g. the client code wishes to perform additional
* validation checks between the fullUrl and the resource id).
*
* @return Returns the parser instance's configuration setting for overriding resource ids with Bundle.entry.fullUrl when
* parsing the source data into a Bundle object. This method will return <code>null</code> if no value is set, in
* which case the value from the {@link ParserOptions} will be used (default is <code>true</code>)
* @see ParserOptions
*/
Boolean getOverrideResourceIdWithBundleEntryFullUrl();
/**
* Is the parser in "summary mode"? See {@link #setSummaryMode(boolean)} for information
*

View File

@ -19,22 +19,25 @@ package ca.uhn.fhir.rest.param;
* limitations under the License.
* #L%
*/
import static org.apache.commons.lang3.StringUtils.defaultString;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.*;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.rest.api.Constants;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import static org.apache.commons.lang3.StringUtils.defaultString;
public class StringParam extends BaseParam implements IQueryParameterType {
private boolean myContains;
private boolean myExact;
private String myValue;
/**
* Constructor
*/
@ -72,6 +75,16 @@ public class StringParam extends BaseParam implements IQueryParameterType {
return ParameterUtil.escape(myValue);
}
@Override
public int hashCode() {
return new HashCodeBuilder(17, 37)
.append(myExact)
.append(myContains)
.append(myValue)
.append(getMissing())
.toHashCode();
}
@Override
void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) {
if (Constants.PARAMQUALIFIER_STRING_EXACT.equals(theQualifier)) {
@ -106,7 +119,7 @@ public class StringParam extends BaseParam implements IQueryParameterType {
eb.append(myContains, other.myContains);
eb.append(myValue, other.myValue);
eb.append(getMissing(), other.getMissing());
return eb.isEquals();
}
@ -114,6 +127,11 @@ public class StringParam extends BaseParam implements IQueryParameterType {
return myValue;
}
public StringParam setValue(String theValue) {
myValue = theValue;
return this;
}
public StringDt getValueAsStringDt() {
return new StringDt(myValue);
}
@ -129,14 +147,6 @@ public class StringParam extends BaseParam implements IQueryParameterType {
return myContains;
}
public boolean isEmpty() {
return StringUtils.isEmpty(myValue);
}
public boolean isExact() {
return myExact;
}
/**
* String parameter modifier <code>:contains</code>
*/
@ -149,6 +159,14 @@ public class StringParam extends BaseParam implements IQueryParameterType {
return this;
}
public boolean isEmpty() {
return StringUtils.isEmpty(myValue);
}
public boolean isExact() {
return myExact;
}
public StringParam setExact(boolean theExact) {
myExact = theExact;
if (myExact) {
@ -158,11 +176,6 @@ public class StringParam extends BaseParam implements IQueryParameterType {
return this;
}
public StringParam setValue(String theValue) {
myValue = theValue;
return this;
}
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);

View File

@ -168,6 +168,8 @@ public class BundleUtil {
BaseRuntimeElementCompositeDefinition<?> entryChildContentsDef = (BaseRuntimeElementCompositeDefinition<?>) entryChildDef.getChildByName("entry");
BaseRuntimeChildDefinition fullUrlChildDef = entryChildContentsDef.getChildByName("fullUrl");
BaseRuntimeChildDefinition resourceChildDef = entryChildContentsDef.getChildByName("resource");
BaseRuntimeChildDefinition requestChildDef = entryChildContentsDef.getChildByName("request");
BaseRuntimeElementCompositeDefinition<?> requestChildContentsDef = (BaseRuntimeElementCompositeDefinition<?>) requestChildDef.getChildByName("request");
@ -180,6 +182,11 @@ public class BundleUtil {
String url = null;
RequestTypeEnum requestType = null;
String conditionalUrl = null;
String fullUrl = fullUrlChildDef
.getAccessor()
.getFirstValueOrNull(nextEntry)
.map(t->((IPrimitiveType<?>)t).getValueAsString())
.orElse(null);
for (IBase nextResource : resourceChildDef.getAccessor().getValues(nextEntry)) {
resource = (IBaseResource) nextResource;
@ -217,7 +224,7 @@ public class BundleUtil {
* order in the original bundle.
*/
BundleEntryMutator mutator = new BundleEntryMutator(nextEntry, requestChildDef, requestChildContentsDef);
ModifiableBundleEntry entry = new ModifiableBundleEntry(new BundleEntryParts(requestType, url, resource, conditionalUrl), mutator);
ModifiableBundleEntry entry = new ModifiableBundleEntry(new BundleEntryParts(fullUrl, requestType, url, resource, conditionalUrl), mutator);
theProcessor.accept(entry);
}
}

View File

@ -28,15 +28,21 @@ public class BundleEntryParts {
private final IBaseResource myResource;
private final String myUrl;
private final String myConditionalUrl;
private final String myFullUrl;
public BundleEntryParts(RequestTypeEnum theRequestType, String theUrl, IBaseResource theResource, String theConditionalUrl) {
public BundleEntryParts(String theFullUrl, RequestTypeEnum theRequestType, String theUrl, IBaseResource theResource, String theConditionalUrl) {
super();
myFullUrl = theFullUrl;
myRequestType = theRequestType;
myUrl = theUrl;
myResource = theResource;
myConditionalUrl = theConditionalUrl;
}
public String getFullUrl() {
return myFullUrl;
}
public RequestTypeEnum getRequestType() {
return myRequestType;
}

View File

@ -21,6 +21,7 @@ package ca.uhn.fhir.util.bundle;
*/
import ca.uhn.fhir.context.FhirContext;
import org.hl7.fhir.instance.model.api.IBaseResource;
public class ModifiableBundleEntry {
private final BundleEntryParts myBundleEntryParts;
@ -39,7 +40,15 @@ public class ModifiableBundleEntry {
myBundleEntryMutator.setRequestUrl(theFhirContext, theRequestUrl);
}
public String getFullUrl() {
return myBundleEntryParts.getFullUrl();
}
public String getRequestUrl() {
return myBundleEntryParts.getUrl();
}
public IBaseResource getResource() {
return myBundleEntryParts.getResource();
}
}

View File

@ -58,7 +58,7 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>@{argLine} -Dfile.encoding=UTF-8 -Xmx712m</argLine>
<argLine>@{argLine} ${surefire_jvm_args}</argLine>
</configuration>
</plugin>
<plugin>

View File

@ -44,7 +44,7 @@ class ConditionalParamBinder implements IParameter {
@Override
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
if (theOuterCollectionType != null || theInnerCollectionType != null || theParameterType.equals(String.class) == false) {
throw new ConfigurationException("Parameters annotated with @" + ConditionalUrlParam.class.getSimpleName() + " must be of type String, found incorrect parameteter in method \"" + theMethod + "\"");
throw new ConfigurationException("Parameters annotated with @" + ConditionalUrlParam.class.getSimpleName() + " must be of type String, found incorrect parameter in method \"" + theMethod + "\"");
}
}

View File

@ -208,23 +208,10 @@ public class MethodUtil {
return b;
}
public static void extractDescription(SearchParameter theParameter, Annotation[] theAnnotations) {
for (Annotation annotation : theAnnotations) {
if (annotation instanceof Description) {
Description desc = (Description) annotation;
if (isNotBlank(desc.formalDefinition())) {
theParameter.setDescription(desc.formalDefinition());
} else {
theParameter.setDescription(desc.shortDefinition());
}
}
}
}
@SuppressWarnings("unchecked")
public static List<IParameter> getResourceParameters(final FhirContext theContext, Method theMethod,
Object theProvider, RestOperationTypeEnum theRestfulOperationTypeEnum) {
List<IParameter> parameters = new ArrayList<IParameter>();
List<IParameter> parameters = new ArrayList<>();
Class<?>[] parameterTypes = theMethod.getParameterTypes();
int paramIndex = 0;
@ -271,7 +258,6 @@ public class MethodUtil {
parameter.setChainlists(((RequiredParam) nextAnnotation).chainWhitelist(),
((RequiredParam) nextAnnotation).chainBlacklist());
parameter.setType(theContext, parameterType, innerCollectionType, outerCollectionType);
MethodUtil.extractDescription(parameter, annotations);
param = parameter;
} else if (nextAnnotation instanceof OptionalParam) {
SearchParameter parameter = new SearchParameter();
@ -282,7 +268,6 @@ public class MethodUtil {
parameter.setChainlists(((OptionalParam) nextAnnotation).chainWhitelist(),
((OptionalParam) nextAnnotation).chainBlacklist());
parameter.setType(theContext, parameterType, innerCollectionType, outerCollectionType);
MethodUtil.extractDescription(parameter, annotations);
param = parameter;
} else if (nextAnnotation instanceof RawParam) {
param = new RawParamsParmeter();

View File

@ -76,7 +76,7 @@ public class JaxRsRestfulClientFactory extends RestfulClientFactory {
}
@Override
public IHttpClient getHttpClient(StringBuilder url, Map<String, List<String>> theIfNoneExistParams, String theIfNoneExistString, RequestTypeEnum theRequestType, List<Header> theHeaders) {
public synchronized IHttpClient getHttpClient(StringBuilder url, Map<String, List<String>> theIfNoneExistParams, String theIfNoneExistString, RequestTypeEnum theRequestType, List<Header> theHeaders) {
Client client = getNativeClientClient();
return new JaxRsHttpClient(client, url, theIfNoneExistParams, theIfNoneExistString, theRequestType, theHeaders);
}
@ -112,7 +112,7 @@ public class JaxRsRestfulClientFactory extends RestfulClientFactory {
@Override
protected JaxRsHttpClient getHttpClient(String theServerBase) {
protected synchronized JaxRsHttpClient getHttpClient(String theServerBase) {
return new JaxRsHttpClient(getNativeClientClient(), new StringBuilder(theServerBase), null, null, null, null);
}

View File

@ -698,7 +698,7 @@
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<runOrder>alphabetical</runOrder>
<argLine>@{argLine} -Dfile.encoding=UTF-8 -Xmx20484M -Xss128M -XX:MetaspaceSize=512M -XX:MaxMetaspaceSize=2048M -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC</argLine>
<argLine>@{argLine} ${surefire_jvm_args}</argLine>
<forkCount>0.6C</forkCount>
<excludes>*StressTest*</excludes>
</configuration>

View File

@ -96,6 +96,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
public static final int DEFAULT_SYNC_SIZE = 250;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchCoordinatorSvcImpl.class);
public static final String UNIT_TEST_CAPTURE_STACK = "unit_test_capture_stack";
private final ConcurrentHashMap<String, SearchTask> myIdToSearchTask = new ConcurrentHashMap<>();
@Autowired
private FhirContext myContext;
@ -902,6 +903,10 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
failureCode = ((BaseServerResponseException) t).getStatusCode();
}
if (System.getProperty(UNIT_TEST_CAPTURE_STACK) != null) {
failureMessage += "\n" + ExceptionUtils.getStackTrace(rootCause);
}
mySearch.setFailureMessage(failureMessage);
mySearch.setFailureCode(failureCode);
mySearch.setStatus(SearchStatusEnum.FAILED);

View File

@ -31,7 +31,7 @@ public interface IValueSetConceptAccumulator {
void includeConcept(String theSystem, String theCode, String theDisplay);
void includeConceptWithDesignations(String theSystem, String theCode, String theDisplay, Collection<TermConceptDesignation> theDesignations);
void includeConceptWithDesignations(String theSystem, String theCode, String theDisplay, @Nullable Collection<TermConceptDesignation> theDesignations);
void excludeConcept(String theSystem, String theCode);

View File

@ -34,7 +34,9 @@ import java.util.Collection;
import java.util.List;
import java.util.Optional;
import static org.apache.commons.lang3.StringUtils.*;
import static org.apache.commons.lang3.StringUtils.isAnyBlank;
import static org.apache.commons.lang3.StringUtils.isNoneBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ValueSetConceptAccumulator.class);
@ -71,8 +73,10 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator {
@Override
public void includeConceptWithDesignations(String theSystem, String theCode, String theDisplay, Collection<TermConceptDesignation> theDesignations) {
TermValueSetConcept concept = saveConcept(theSystem, theCode, theDisplay);
for (TermConceptDesignation designation : theDesignations) {
saveConceptDesignation(concept, designation);
if (theDesignations != null) {
for (TermConceptDesignation designation : theDesignations) {
saveConceptDesignation(concept, designation);
}
}
}

View File

@ -25,7 +25,6 @@ import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.term.IRecordHandler;
import org.apache.commons.csv.CSVRecord;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.r4.model.ValueSet;
import java.util.HashMap;
import java.util.Map;
@ -37,7 +36,6 @@ public class LoincPartHandler implements IRecordHandler {
private final Map<String, TermConcept> myCode2Concept;
private final TermCodeSystemVersion myCodeSystemVersion;
private final Map<String, ValueSet> myIdToValueSet = new HashMap<>();
private final Map<PartTypeAndPartName, String> myPartTypeAndPartNameToPartNumber = new HashMap<>();
public LoincPartHandler(TermCodeSystemVersion theCodeSystemVersion, Map<String, TermConcept> theCode2concept) {

View File

@ -5,6 +5,7 @@ import ca.uhn.fhir.jpa.model.entity.*;
import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap.EverythingModeEnum;
import ca.uhn.fhir.jpa.searchparam.registry.SearchParamRegistryImpl;
import ca.uhn.fhir.jpa.util.TestUtil;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
@ -229,6 +230,36 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
}
@Test
public void testHasChain() {
Patient p = new Patient();
p.setId("P");
p.setActive(true);
myPatientDao.update(p);
Group group = new Group();
group.setId("G");
group.addMember().getEntity().setReference("Patient/P");
myGroupDao.update(group);
DiagnosticReport dr = new DiagnosticReport();
dr.setId("DR");
dr.getSubject().setReference("Patient/P");
myDiagnosticReportDao.update(dr);
SearchParameterMap map = new SearchParameterMap();
map.setLoadSynchronous(true);
ReferenceParam referenceParam = new ReferenceParam();
referenceParam.setValueAsQueryToken(myFhirCtx, "subject", "._has:Group:member:_id", "Group/G");
map.add("subject", referenceParam);
List<String> actual = toUnqualifiedVersionlessIdValues(myDiagnosticReportDao.search(map));
assertThat(actual, containsInAnyOrder("DiagnosticReport/DR"));
// http://hapi.fhir.org/baseR4/DiagnosticReport?subject._has:Group:member:_id=52152
}
@SuppressWarnings("unused")
@Test
public void testHasAndHas() {

View File

@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.DaoMethodOutcome;
import ca.uhn.fhir.jpa.entity.Search;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
@ -2154,6 +2155,27 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
}
@Test
public void testSearchResourceLinkOnCanonical() {
Questionnaire q = new Questionnaire();
q.setId("Q");
myQuestionnaireDao.update(q);
QuestionnaireResponse qr = new QuestionnaireResponse();
qr.setId("QR");
qr.setQuestionnaire("Questionnaire/Q");
String qrId = myQuestionnaireResponseDao.update(qr).getId().toUnqualifiedVersionless().getValue();
List<QuestionnaireResponse> result = toList(myQuestionnaireResponseDao
.search(new SearchParameterMap().setLoadSynchronous(true).add(QuestionnaireResponse.SP_QUESTIONNAIRE, new ReferenceParam("Questionnaire/Q"))));
assertEquals(1, result.size());
assertEquals(qrId, result.get(0).getIdElement().toUnqualifiedVersionless().getValue());
}
@Test
public void testSearchResourceLinkWithChain() {
Patient patient = new Patient();

View File

@ -10,6 +10,8 @@ import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
import ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl;
import ca.uhn.fhir.jpa.term.api.ITermReadSvc;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
@ -116,6 +118,8 @@ public class FhirResourceDaoR4SearchWithLuceneDisabledTest extends BaseJpaTest {
private IResourceReindexingSvc myResourceReindexingSvc;
@Autowired
private IBulkDataExportSvc myBulkDataExportSvc;
@Autowired
private ITermReadSvc myTermSvc;
@Before
@Transactional()
@ -190,6 +194,36 @@ public class FhirResourceDaoR4SearchWithLuceneDisabledTest extends BaseJpaTest {
}
}
@Test
public void testExpandValueSet() {
CodeSystem cs = new CodeSystem();
cs.setUrl("http://fooCS");
cs.setContent(CodeSystem.CodeSystemContentMode.COMPLETE);
cs.addConcept().setCode("CODEA");
cs.addConcept().setCode("CODEB");
myCodeSystemDao.create(cs);
ValueSet vs = new ValueSet();
vs.setUrl("http://fooVS");
vs.getCompose()
.addInclude()
.setSystem("http://fooCS")
.addConcept(new ValueSet.ConceptReferenceComponent().setCode("CODEA"));
// Explicit expand
ValueSet outcome = myValueSetDao.expand(vs, null);
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
assertEquals("CODEA", outcome.getExpansion().getContains().get(0).getCode());
// Deferred expand
IIdType id = myValueSetDao.create(vs).getId().toUnqualifiedVersionless();
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
outcome = myValueSetDao.expand(id, null, mySrd);
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
assertEquals("CODEA", outcome.getExpansion().getContains().get(0).getCode());
}
@Test
public void testSearchByCodeIn() {
CodeSystem cs = new CodeSystem();
@ -207,6 +241,7 @@ public class FhirResourceDaoR4SearchWithLuceneDisabledTest extends BaseJpaTest {
.addConcept(new ValueSet.ConceptReferenceComponent().setCode("CODEA"));
myValueSetDao.create(vs);
Observation obs = new Observation();
obs.getCode().addCoding().setSystem("http://fooCS").setCode("CODEA");
String obs1id = myObservationDao.create(obs).getId().toUnqualifiedVersionless().getValue();

View File

@ -77,11 +77,14 @@ public class SearchCoordinatorSvcImplTest {
@After
public void after() {
System.clearProperty(SearchCoordinatorSvcImpl.UNIT_TEST_CAPTURE_STACK);
verify(myCallingDao, atMost(myExpectedNumberOfSearchBuildersCreated)).newSearchBuilder();
}
@Before
public void before() {
System.setProperty(SearchCoordinatorSvcImpl.UNIT_TEST_CAPTURE_STACK, "true");
myCurrentSearch = null;
mySvc = new SearchCoordinatorSvcImpl();
@ -148,7 +151,8 @@ public class SearchCoordinatorSvcImplTest {
try {
result.getResources(0, 100000);
} catch (InternalErrorException e) {
assertEquals("FAILED", e.getMessage());
assertThat(e.getMessage(), containsString("FAILED"));
assertThat(e.getMessage(), containsString("at ca.uhn.fhir.jpa.search.SearchCoordinatorSvcImplTest"));
}
}
@ -187,9 +191,7 @@ public class SearchCoordinatorSvcImplTest {
when(mySearchResultCacheSvc.fetchAllResultPids(any())).thenReturn(allResults);
when(mySearchCacheSvc.tryToMarkSearchAsInProgress(any())).thenAnswer(t->{
Object argument = t.getArgument(0);
Validate.isTrue( argument instanceof Search, "Argument is " + argument);
Search search = (Search) argument;
Search search = t.getArgument(0, Search.class);
assertEquals(SearchStatusEnum.PASSCMPLET, search.getStatus());
search.setStatus(SearchStatusEnum.LOADING);
return Optional.of(search);
@ -202,7 +204,7 @@ public class SearchCoordinatorSvcImplTest {
List<IBaseResource> resources;
when(mySearchCacheSvc.save(any())).thenAnswer(t -> {
Search search = (Search) t.getArguments()[0];
Search search = t.getArgument(0, Search.class);
myCurrentSearch = search;
return search;
});
@ -328,7 +330,8 @@ public class SearchCoordinatorSvcImplTest {
try {
result.getResources(10, 20);
} catch (InternalErrorException e) {
assertEquals("Abort has been requested", e.getMessage());
assertThat(e.getMessage(), containsString("Abort has been requested"));
assertThat(e.getMessage(), containsString("at ca.uhn.fhir.jpa.search.SearchCoordinatorSvcImpl"));
}
completionLatch.await(10, TimeUnit.SECONDS);

View File

@ -2666,7 +2666,7 @@
"fullUrl": "http://fhirtest.uhn.ca/baseDstu3/Practitioner/A45515",
"resource": {
"resourceType": "Practitioner",
"id": "45515",
"id": "A45515",
"meta": {
"versionId": "1",
"lastUpdated": "2016-05-07T11:45:53.918-04:00"

View File

@ -160,7 +160,7 @@
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<runOrder>alphabetical</runOrder>
<argLine>@{argLine} -Dfile.encoding=UTF-8 -Xmx20484M -Xss128M -XX:MetaspaceSize=512M -XX:MaxMetaspaceSize=2048M -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC</argLine>
<argLine>@{argLine} ${surefire_jvm_args}</argLine>
<forkCount>0.6C</forkCount>
<excludes>*StressTest*</excludes>
</configuration>

View File

@ -23,6 +23,8 @@ package ca.uhn.fhir.jpa.searchparam;
import ca.uhn.fhir.model.api.IQueryParameterAnd;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.param.HasAndListParam;
import ca.uhn.fhir.rest.param.HasParam;
import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenAndListParam;
@ -61,6 +63,8 @@ public class ResourceMetaParams {
resourceMetaAndParams.put(Constants.PARAM_PROFILE, UriAndListParam.class);
resourceMetaParams.put(Constants.PARAM_SECURITY, TokenParam.class);
resourceMetaAndParams.put(Constants.PARAM_SECURITY, TokenAndListParam.class);
resourceMetaParams.put(Constants.PARAM_HAS, HasParam.class);
resourceMetaAndParams.put(Constants.PARAM_HAS, HasAndListParam.class);
RESOURCE_META_PARAMS = Collections.unmodifiableMap(resourceMetaParams);
RESOURCE_META_AND_PARAMS = Collections.unmodifiableMap(resourceMetaAndParams);

View File

@ -51,6 +51,7 @@ import org.hl7.fhir.instance.model.api.IBaseReference;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.hl7.fhir.r4.model.IdType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
@ -151,7 +152,31 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
String nextType = toRootTypeName(value);
switch (nextType) {
case "uri":
case "canonical":
String typeName = toTypeName(value);
// Canonical has a root type of "uri"
if ("canonical".equals(typeName)) {
IPrimitiveType<?> valuePrimitive = (IPrimitiveType<?>) value;
IBaseReference fakeReference = (IBaseReference) myContext.getElementDefinition("Reference").newInstance();
fakeReference.setReference(valuePrimitive.getValueAsString());
/*
* See #1583
* Technically canonical fields should not allow local references (e.g.
* Questionnaire/123) but it seems reasonable for us to interpret a canonical
* containing a local reference for what it is, and allow people to seaerch
* based on that.
*/
IIdType parsed = fakeReference.getReferenceElement();
if (parsed.hasIdPart() && parsed.hasResourceType() && !parsed.isAbsolute()) {
PathAndRef ref = new PathAndRef(searchParam.getName(), path, fakeReference);
params.add(ref);
break;
}
}
params.addWarning("Ignoring canonical reference (indexing canonical is not yet supported)");
break;
case "reference":
@ -789,6 +814,11 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
return rootParentDefinition.getName();
}
private String toTypeName(IBase nextObject) {
BaseRuntimeElementDefinition<?> elementDefinition = getContext().getElementDefinition(nextObject.getClass());
return elementDefinition.getName();
}
@SuppressWarnings("unchecked")
private void addDateTimeTypes(String theResourceType, Set<ResourceIndexedSearchParamDate> theParams, RuntimeSearchParam theSearchParam, IBase theValue) {
IPrimitiveType<Date> nextBaseDateTime = (IPrimitiveType<Date>) theValue;

View File

@ -97,7 +97,7 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>@{argLine} -Dfile.encoding=UTF-8 -Xmx712m</argLine>
<argLine>@{argLine} ${surefire_jvm_args}</argLine>
</configuration>
</plugin>
<plugin>

View File

@ -47,7 +47,7 @@ class ConditionalParamBinder implements IParameter {
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
if (theOuterCollectionType != null || theInnerCollectionType != null || theParameterType.equals(String.class) == false) {
throw new ConfigurationException(
"Parameters annotated with @" + ConditionalUrlParam.class.getSimpleName() + " must be of type String, found incorrect parameteter in method \"" + theMethod + "\"");
"Parameters annotated with @" + ConditionalUrlParam.class.getSimpleName() + " must be of type String, found incorrect parameter in method \"" + theMethod + "\"");
}
}

View File

@ -28,6 +28,8 @@ import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.annotation.OptionalParam;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
@ -91,6 +93,14 @@ public class OperationMethodBinding extends BaseResourceReturningMethodBinding {
myDescription = null;
}
for (Annotation[] nextParamAnnotations : theMethod.getParameterAnnotations()) {
for (Annotation nextParam : nextParamAnnotations) {
if (nextParam instanceof OptionalParam || nextParam instanceof RequiredParam) {
throw new ConfigurationException("Illegal method parameter annotation @" + nextParam.annotationType().getSimpleName() + " on method: " + theMethod.toString());
}
}
}
if (isBlank(theOperationName)) {
throw new ConfigurationException("Method '" + theMethod.getName() + "' on type " + theMethod.getDeclaringClass().getName() + " is annotated with @" + Operation.class.getSimpleName()
+ " but this annotation has no name defined");

View File

@ -186,7 +186,7 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>@{argLine} -Dfile.encoding=UTF-8 -Xmx712m</argLine>
<argLine>@{argLine} ${surefire_jvm_args}</argLine>
</configuration>
</plugin>
<plugin>

View File

@ -270,7 +270,7 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>@{argLine} -Dfile.encoding=UTF-8 -Xmx712m</argLine>
<argLine>@{argLine} ${surefire_jvm_args}</argLine>
</configuration>
</plugin>
<plugin>

View File

@ -244,7 +244,7 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Dfile.encoding=UTF-8 -Xmx1024m</argLine>
<argLine>@{argLine} ${surefire_jvm_args}</argLine>
</configuration>
</plugin>
<plugin>

View File

@ -71,7 +71,7 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>@{argLine} -Dfile.encoding=UTF-8 -Xmx712m</argLine>
<argLine>@{argLine} ${surefire_jvm_args}</argLine>
</configuration>
</plugin>
<plugin>
@ -150,7 +150,7 @@
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<version>3.1.0</version>
<optional>true</optional>
</dependency>

View File

@ -269,7 +269,7 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>@{argLine} -Dfile.encoding=UTF-8 -Xmx712m</argLine>
<argLine>@{argLine} ${surefire_jvm_args}</argLine>
</configuration>
</plugin>
<plugin>

View File

@ -315,7 +315,7 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>@{argLine} -Dfile.encoding=UTF-8 -Xmx712m</argLine>
<argLine>@{argLine} ${surefire_jvm_args}</argLine>
</configuration>
</plugin>
<plugin>

View File

@ -23,6 +23,7 @@ import java.util.Set;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.stringContainsInOrder;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
@ -174,6 +175,34 @@ public class JsonParserR4Test extends BaseTest {
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">Copy © 1999</div>", p.getText().getDivAsString());
}
@Test
public void testEncodeAndParseBundleWithFullUrlAndResourceIdMismatch() {
MessageHeader header = new MessageHeader();
header.setId("1.1.1.1");
header.setDefinition("Hello");
Bundle input = new Bundle();
input
.addEntry()
.setFullUrl("urn:uuid:0.0.0.0")
.setResource(header);
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(input);
ourLog.info("Encoded: {}", encoded);
assertThat(encoded, stringContainsInOrder(
"\"fullUrl\": \"urn:uuid:0.0.0.0\"",
"\"id\": \"1.1.1.1\""
));
input = ourCtx.newJsonParser().parseResource(Bundle.class, encoded);
assertEquals("urn:uuid:0.0.0.0", input.getEntry().get(0).getFullUrl());
assertEquals("MessageHeader/1.1.1.1", input.getEntry().get(0).getResource().getId());
}
@Test
public void testEncodeBinary() {
Binary b = new Binary();

View File

@ -1,8 +1,13 @@
package ca.uhn.fhir.parser;
import static org.hamcrest.Matchers.stringContainsInOrder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThat;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Composition;
import org.hl7.fhir.r4.model.MessageHeader;
import org.hl7.fhir.r4.model.Narrative;
import org.junit.Test;
import org.slf4j.Logger;
@ -41,5 +46,33 @@ public class XmlParserR4Test {
int idx = encoded.indexOf(sectionText);
assertNotEquals(-1, idx);
}
@Test
public void testEncodeAndParseBundleWithFullUrlAndResourceIdMismatch() {
MessageHeader header = new MessageHeader();
header.setId("1.1.1.1");
header.setDefinition("Hello");
Bundle input = new Bundle();
input
.addEntry()
.setFullUrl("urn:uuid:0.0.0.0")
.setResource(header);
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(input);
ourLog.info("Encoded: {}", encoded);
assertThat(encoded, stringContainsInOrder(
"<fullUrl value=\"urn:uuid:0.0.0.0\"/>",
"<id value=\"1.1.1.1\"/>"
));
input = ourCtx.newXmlParser().parseResource(Bundle.class, encoded);
assertEquals("urn:uuid:0.0.0.0", input.getEntry().get(0).getFullUrl());
assertEquals("MessageHeader/1.1.1.1", input.getEntry().get(0).getResource().getId());
}
}

View File

@ -1,14 +1,21 @@
package ca.uhn.fhir.rest.client;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.rest.annotation.*;
import ca.uhn.fhir.rest.annotation.Elements;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.IncludeParam;
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.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.apache.ApacheHttpRequest;
import ca.uhn.fhir.rest.client.apache.ResourceEntity;
import ca.uhn.fhir.rest.client.api.IBasicClient;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
@ -47,13 +54,24 @@ import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.util.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.either;
import static org.hamcrest.Matchers.equalTo;
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.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -144,7 +162,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), StandardCharsets.UTF_8));
when(myHttpResponse.getAllHeaders()).thenReturn(toHeaderArray("Location", "http://example.com/fhir/Patient/100/_history/200"));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
@ -173,7 +191,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 400, "foobar"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("foobar"), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("foobar"), StandardCharsets.UTF_8));
try {
ourCtx.newRestfulClient(ITestClient.class, "http://foo").createPatient(patient);
@ -197,7 +215,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(ourCtx.newXmlParser().encodeResourceToString(patient)), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(ourCtx.newXmlParser().encodeResourceToString(patient)), StandardCharsets.UTF_8));
when(myHttpResponse.getAllHeaders()).thenReturn(toHeaderArray("Location", "http://example.com/fhir/Patient/100/_history/200"));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
@ -221,7 +239,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(resp), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(resp), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
MethodOutcome response = client.deletePatient(new IdType("1234"));
@ -238,7 +256,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 204, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
client.deleteDiagnosticReport(new IdType("1234"));
@ -259,7 +277,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
CapabilityStatement response = (CapabilityStatement) client.getServerConformanceStatement();
@ -278,7 +296,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML_NEW + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
Bundle response = client.getHistoryPatientInstance(new IdType("111"));
@ -298,7 +316,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML_NEW + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
Bundle response = client.getHistoryPatientType();
@ -316,7 +334,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML_NEW + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
Bundle response = client.getHistoryServer();
@ -340,7 +358,7 @@ public class ClientR4Test {
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<InputStream>() {
@Override
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"));
return new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8);
}
});
@ -410,7 +428,7 @@ public class ClientR4Test {
when(myHttpResponse.getAllHeaders()).thenReturn(headers);
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
// Patient response = client.findPatientByMrn(new
@ -422,7 +440,7 @@ public class ClientR4Test {
assertEquals("http://foo.com/Patient/123/_history/2333", response.getId());
InstantType lm = (InstantType) response.getMeta().getLastUpdatedElement();
InstantType lm = response.getMeta().getLastUpdatedElement();
lm.setTimeZoneZulu(true);
assertEquals("1995-11-15T04:58:08.000Z", lm.getValueAsString());
@ -447,7 +465,7 @@ public class ClientR4Test {
headers[0] = new BasicHeader(Constants.HEADER_LAST_MODIFIED, "2011-01-02T22:01:02");
when(myHttpResponse.getAllHeaders()).thenReturn(headers);
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("Internal Failure"), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("Internal Failure"), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
try {
@ -474,7 +492,7 @@ public class ClientR4Test {
headers[0] = new BasicHeader(Constants.HEADER_LAST_MODIFIED, "2011-01-02T22:01:02");
when(myHttpResponse.getAllHeaders()).thenReturn(headers);
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
try {
@ -498,7 +516,7 @@ public class ClientR4Test {
headers[0] = new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08 GMT");
when(myHttpResponse.getAllHeaders()).thenReturn(headers);
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
// Patient response = client.findPatientByMrn(new
@ -508,7 +526,7 @@ public class ClientR4Test {
assertEquals("http://foo/Patient/111", capt.getValue().getURI().toString());
assertEquals("PRP1660", response.getIdentifier().get(0).getValueElement().getValue());
InstantType lm = (InstantType) response.getMeta().getLastUpdatedElement();
InstantType lm = response.getMeta().getLastUpdatedElement();
lm.setTimeZoneZulu(true);
assertEquals("1995-11-15T04:58:08.000Z", lm.getValueAsString());
@ -523,7 +541,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", "application/fhir+xml; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
// Patient response = client.findPatientByMrn(new
@ -544,7 +562,7 @@ public class ClientR4Test {
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
@ -572,7 +590,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
StringParam str = new StringParam("FOO$BAR");
@ -592,7 +610,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
DateRangeParam param = new DateRangeParam();
@ -613,7 +631,7 @@ public class ClientR4Test {
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
// httpResponse = new BasicHttpResponse(statusline, catalog, locale)
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
@ -635,7 +653,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
Patient response = client.findPatientQuantity(new QuantityParam(ParamPrefixEnum.GREATERTHAN, 123L, "foo", "bar"));
@ -654,7 +672,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
Patient response = client.findPatientByMrn(new TokenParam("urn:foo", "123"));
@ -673,7 +691,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
client.getPatientNoParams();
@ -691,7 +709,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
client.getPatientOneParam(new StringParam("BB"));
@ -709,7 +727,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
TokenOrListParam identifiers = new TokenOrListParam();
@ -730,7 +748,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClientWithCustomType client = ourCtx.newRestfulClient(ITestClientWithCustomType.class, "http://foo");
CustomPatient response = client.getPatientByDob(new DateParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, "2011-01-02"));
@ -749,7 +767,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClientWithCustomTypeList client = ourCtx.newRestfulClient(ITestClientWithCustomTypeList.class, "http://foo");
List<CustomPatient> response = client.getPatientByDob(new DateParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, "2011-01-02"));
@ -771,7 +789,7 @@ public class ClientR4Test {
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<InputStream>() {
@Override
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"));
return new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8);
}
});
@ -813,7 +831,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
StringAndListParam andListParam = new StringAndListParam();
@ -837,7 +855,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
// TODO: document this
@ -845,13 +863,13 @@ public class ClientR4Test {
client.getPatientByDob(new DateParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, "2011-01-02"));
assertEquals("http://foo/Patient?birthdate=ge2011-01-02", capt.getAllValues().get(0).getURI().toString());
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
client.setEncoding(EncodingEnum.JSON); // this needs to be actually
// implemented
client.getPatientByDob(new DateParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, "2011-01-02"));
assertEquals("http://foo/Patient?birthdate=ge2011-01-02&_format=json", capt.getAllValues().get(1).getURI().toString());
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
client.setPrettyPrint(true);
client.getPatientByDob(new DateParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, "2011-01-02"));
assertEquals("http://foo/Patient?birthdate=ge2011-01-02&_format=json&_pretty=true", capt.getAllValues().get(2).getURI().toString());
@ -877,7 +895,7 @@ public class ClientR4Test {
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
// httpResponse = new BasicHttpResponse(statusline, catalog, locale)
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
@ -900,7 +918,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
client.setSummary(SummaryEnum.DATA);
@ -919,10 +937,10 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
client.getPatientWithIncludes(new StringParam("aaa"), Arrays.asList(new Include[]{new Include("inc1"), new Include("inc2", true), new Include("inc3", true)}));
client.getPatientWithIncludes(new StringParam("aaa"), Arrays.asList(new Include("inc1"), new Include("inc2", true), new Include("inc3", true)));
assertEquals("http://foo/Patient?withIncludes=aaa&_include=inc1&_include%3Aiterate=inc2&_include%3Aiterate=inc3", capt.getValue().getURI().toString());
@ -937,7 +955,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
Bundle response = client.findPatientByName(new StringParam("AAA"), null);
@ -950,7 +968,7 @@ public class ClientR4Test {
* Now with a first name
*/
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
response = client.findPatientByName(new StringParam("AAA"), new StringParam("BBB"));
@ -970,7 +988,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClientWithStringIncludes client = ourCtx.newRestfulClient(ITestClientWithStringIncludes.class, "http://foo");
client.getPatientWithIncludes(new StringParam("aaa"), "inc1");
@ -991,7 +1009,7 @@ public class ClientR4Test {
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<InputStream>() {
@Override
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"));
return new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8);
}
});
@ -1037,7 +1055,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), StandardCharsets.UTF_8));
when(myHttpResponse.getAllHeaders()).thenReturn(toHeaderArray("Location", "http://example.com/fhir/Patient/100/_history/200"));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
@ -1065,7 +1083,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), StandardCharsets.UTF_8));
when(myHttpResponse.getAllHeaders()).thenReturn(toHeaderArray(Constants.HEADER_LOCATION, "http://example.com/fhir/Patient/100/_history/200"));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
@ -1088,7 +1106,7 @@ public class ClientR4Test {
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), StandardCharsets.UTF_8));
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), Constants.STATUS_HTTP_409_CONFLICT, "Conflict"));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
@ -1105,7 +1123,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), StandardCharsets.UTF_8));
when(myHttpResponse.getAllHeaders()).thenReturn(toHeaderArray("Location", "http://example.com/fhir/Patient/100/_history/200"));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
@ -1129,7 +1147,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), Constants.STATUS_HTTP_204_NO_CONTENT, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), StandardCharsets.UTF_8));
when(myHttpResponse.getAllHeaders()).thenReturn(toHeaderArray("Location", "http://example.com/fhir/Patient/100/_history/200"));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
@ -1152,7 +1170,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(response), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(response), StandardCharsets.UTF_8));
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE);
IGenericClient client = ourCtx.newRestfulGenericClient("http://testValidateServerBaseWithInvalidResponse");
@ -1180,7 +1198,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_JSON_NEW + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(resp), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(resp), StandardCharsets.UTF_8));
when(myHttpResponse.getAllHeaders()).thenReturn(toHeaderArray("Location", "http://example.com/fhir/Patient/100/_history/200"));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
@ -1215,7 +1233,7 @@ public class ClientR4Test {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
// Patient response = client.findPatientByMrn(new
@ -1227,6 +1245,67 @@ public class ClientR4Test {
}
@Test
public void testClientWithAndOrList() throws IOException {
Bundle response = new Bundle().setType(Bundle.BundleType.SEARCHSET);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity()).thenReturn(new ResourceEntity(ourCtx, response));
ITestClientWithAndOr client = ourCtx.newRestfulClient(ITestClientWithAndOr.class, "http://foo");
StringAndListParam andList = new StringAndListParam();
StringOrListParam orListA = new StringOrListParam();
orListA.add(new StringParam("A1"));
orListA.add(new StringParam("A2"));
andList.addAnd(orListA);
StringOrListParam orListB = new StringOrListParam();
orListB.add(new StringParam("B1"));
orListB.add(new StringParam("B2"));
andList.addAnd(orListB);
client.search(andList);
assertEquals("http://foo/Patient?foo=A1%2CA2&foo=B1%2CB2", capt.getValue().getURI().toString());
}
@Test
public void testClientWithAndOrList2() throws IOException {
Bundle response = new Bundle().setType(Bundle.BundleType.SEARCHSET);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity()).thenReturn(new ResourceEntity(ourCtx, response));
try {
ourCtx.newRestfulClient(ITestClientWithAndOr2.class, "http://foo");
} catch (ConfigurationException e) {
assertEquals("Argument #0 of Method 'search' in type 'ca.uhn.fhir.rest.client.ClientR4Test.ITestClientWithAndOr2' is of an invalid generic type (can not be a collection of a collection of a collection)", e.getMessage());
}
}
@Test
public void testClientWithAndOrList3() throws IOException {
Bundle response = new Bundle().setType(Bundle.BundleType.SEARCHSET);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity()).thenReturn(new ResourceEntity(ourCtx, response));
ITestClientWithAndOr3 client = ourCtx.newRestfulClient(ITestClientWithAndOr3.class, "http://foo");
Set<Include> orListA = new HashSet<>();
orListA.add(new Include("a"));
orListA.add(new Include("b"));
client.search(orListA);
assertEquals("http://foo/Patient?_include=a&_include=b", capt.getValue().getURI().toString());
}
private Header[] toHeaderArray(String theName, String theValue) {
return new Header[]{new BasicHeader(theName, theValue)};
}
@ -1245,40 +1324,61 @@ public class ClientR4Test {
}
}
interface ITestClientWithAndOr extends IBasicClient {
@Search()
List<Patient> search(@OptionalParam(name = "foo") StringAndListParam theParam);
}
interface ITestClientWithAndOr2 extends IBasicClient {
@Search()
List<Patient> search(@OptionalParam(name = "foo") List<List<String>> theParam);
}
public interface ITestClientWithAndOr3 extends IBasicClient {
@Search()
List<Patient> search(@IncludeParam Set<Include> theParam);
}
private interface ClientWithoutAnnotation extends IBasicClient {
Patient read(@IdParam IdType theId);
}
public interface ITestClientWithCustomType extends IBasicClient {
@Search()
public CustomPatient getPatientByDob(@RequiredParam(name = Patient.SP_BIRTHDATE) DateParam theBirthDate);
CustomPatient getPatientByDob(@RequiredParam(name = Patient.SP_BIRTHDATE) DateParam theBirthDate);
}
public interface ITestClientWithCustomTypeList extends IBasicClient {
@Search()
public List<CustomPatient> getPatientByDob(@RequiredParam(name = Patient.SP_BIRTHDATE) DateParam theBirthDate);
List<CustomPatient> getPatientByDob(@RequiredParam(name = Patient.SP_BIRTHDATE) DateParam theBirthDate);
}
public interface ITestClientWithElements extends IBasicClient {
@Search()
public List<Patient> getPatientWithIncludes(@Elements Set<String> theElements);
List<Patient> getPatientWithIncludes(@Elements Set<String> theElements);
@Search()
public List<Patient> getPatientWithIncludes(@Elements String theElements);
List<Patient> getPatientWithIncludes(@Elements String theElements);
}
public interface ITestClientWithStringIncludes extends IBasicClient {
@Search()
public Patient getPatientWithIncludes(@RequiredParam(name = "withIncludes") StringParam theString, @IncludeParam String theInclude);
Patient getPatientWithIncludes(@RequiredParam(name = "withIncludes") StringParam theString, @IncludeParam String theInclude);
}
public interface ITestClientWithSummary extends IBasicClient {
@Search()
public List<Patient> getPatientWithIncludes(List<SummaryEnum> theSummary);
List<Patient> getPatientWithIncludes(List<SummaryEnum> theSummary);
@Search()
public List<Patient> getPatientWithIncludes(SummaryEnum theSummary);
List<Patient> getPatientWithIncludes(SummaryEnum theSummary);
}

View File

@ -0,0 +1,113 @@
package ca.uhn.fhir.rest.server;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.annotation.Transaction;
import ca.uhn.fhir.rest.annotation.TransactionParam;
import ca.uhn.fhir.test.utilities.server.ResourceProviderRule;
import ca.uhn.fhir.test.utilities.server.RestfulServerRule;
import com.google.common.base.Charsets;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Patient;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
public class BlockingContentR4Test {
private static final Logger ourLog = LoggerFactory.getLogger(BlockingContentR4Test.class);
private static FhirContext ourCtx = FhirContext.forR4();
@ClassRule
public static RestfulServerRule ourServerRule = new RestfulServerRule(ourCtx);
@Rule
public ResourceProviderRule myPatientProviderRule = new ResourceProviderRule(ourServerRule, new SystemProvider());
@Test
public void testCreateWith100Continue() throws Exception {
Patient patient = new Patient();
patient.setActive(true);
Bundle input = new Bundle();
input.setType(Bundle.BundleType.TRANSACTION);
input.addEntry().setResource(patient).setFullUrl("Patient/").getRequest().setMethod(Bundle.HTTPVerb.POST);
RequestConfig config = RequestConfig.custom().setExpectContinueEnabled(true).build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setConnectionManager(connectionManager);
builder.setDefaultRequestConfig(config);
try (CloseableHttpClient client = builder.build()) {
String resourceAsString = ourCtx.newJsonParser().encodeResourceToString(input);
// InputStream inputStream = new BlockingInputStream(resourceAsString.getBytes(Charsets.UTF_8));
byte[] bytes = resourceAsString.getBytes(Charsets.UTF_8);
InputStream inputStream = new ByteArrayInputStream(bytes);
HttpEntity entity = new InputStreamEntity(inputStream, ContentType.parse("application/fhir+json")){
@Override
public long getContentLength() {
return bytes.length + 100;
}
};
HttpPost post = new HttpPost("http://localhost:" + ourServerRule.getPort() + "/");
post.setEntity(entity);
try (CloseableHttpResponse resp = client.execute(post)) {
ourLog.info(Arrays.asList(resp.getAllHeaders()).toString().replace(", ", "\n"));
ourLog.info(resp.toString());
ourLog.info(IOUtils.toString(resp.getEntity().getContent(), Charsets.UTF_8));
}
}
}
private static class BlockingInputStream extends InputStream {
private final ByteArrayInputStream myWrap;
private int myByteCount = 0;
public BlockingInputStream(byte[] theBytes) {
myWrap = new ByteArrayInputStream(theBytes);
}
@Override
public int read() throws IOException {
if (myByteCount++ == 10) {
ourLog.info("About to block...");
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
ourLog.warn("Interrupted", e);
}
}
return myWrap.read();
}
}
public static class SystemProvider {
@Transaction
public Bundle transaction(@TransactionParam Bundle theInput) {
return theInput;
}
}
}

View File

@ -1,30 +1,30 @@
package ca.uhn.fhir.rest.server;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OptionalParam;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Update;
import ca.uhn.fhir.rest.annotation.Validate;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.util.TestUtil;
import org.hamcrest.core.StringContains;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.StringType;
import org.junit.AfterClass;
import org.junit.Test;
import javax.servlet.ServletException;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import javax.servlet.ServletException;
public class ServerInvalidDefinitionR4Test {
import org.hamcrest.core.StringContains;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.AfterClass;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.rest.annotation.*;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.util.TestUtil;
public class ServerInvalidDefinitionDstu2Test {
private static FhirContext ourCtx = FhirContext.forDstu2();
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
}
private static FhirContext ourCtx = FhirContext.forR4();
@Test
public void testWrongConditionalUrlType() {
@ -38,7 +38,7 @@ public class ServerInvalidDefinitionDstu2Test {
} catch (ServletException e) {
assertThat(e.getCause().toString(), StringContains.containsString("ConfigurationException"));
assertThat(e.getCause().toString(), StringContains.containsString(
"Parameters annotated with @ConditionalUrlParam must be of type String, found incorrect parameteter in method \"public ca.uhn.fhir.rest.api.MethodOutcome ca.uhn.fhir.rest.server.ServerInvalidDefinitionDstu2Test$UpdateWithWrongConditionalUrlType.update(ca.uhn.fhir.rest.param.TokenParam,ca.uhn.fhir.model.dstu2.resource.Patient)"));
"Parameters annotated with @ConditionalUrlParam must be of type String, found incorrect parameter in method \"public ca.uhn.fhir.rest.api.MethodOutcome ca.uhn.fhir.rest.server.ServerInvalidDefinitionR4Test$UpdateWithWrongConditionalUrlType.update(ca.uhn.fhir.rest.param.TokenParam,org.hl7.fhir.r4.model.Patient)"));
}
}
@ -54,7 +54,7 @@ public class ServerInvalidDefinitionDstu2Test {
} catch (ServletException e) {
assertThat(e.getCause().toString(), StringContains.containsString("ConfigurationException"));
assertThat(e.getCause().toString(), StringContains
.containsString("Method 'update' is annotated with @ResourceParam but has a type that is not an implemtation of org.hl7.fhir.instance.model.api.IBaseResource or String or byte[]"));
.containsString("Method 'update' is annotated with @ResourceParam but has a type that is not an implemtation of org.hl7.fhir.instance.model.api.IBaseResource or String or byte[]"));
}
}
@ -88,6 +88,29 @@ public class ServerInvalidDefinitionDstu2Test {
}
}
@Test
public void testWrongParameterAnnotationOnOperation() {
class MyProvider {
@Operation(name = "foo")
public MethodOutcome update(@OptionalParam(name = "foo") StringType theFoo) {
return null;
}
}
RestfulServer srv = new RestfulServer(ourCtx);
srv.setFhirContext(ourCtx);
srv.registerProvider(new MyProvider());
try {
srv.init();
fail();
} catch (ServletException e) {
assertThat(e.getCause().toString(), StringContains.containsString("Failure scanning class MyProvider: Illegal method parameter annotation @OptionalParam on method: public ca.uhn.fhir.rest.api.MethodOutcome ca.uhn.fhir.rest.server.ServerInvalidDefinitionR4Test$1MyProvider.update(org.hl7.fhir.r4.model.StringType)"));
}
}
public static class UpdateWithWrongConditionalUrlType implements IResourceProvider {
@Override
@ -144,4 +167,9 @@ public class ServerInvalidDefinitionDstu2Test {
}
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
}
}

View File

@ -1,18 +1,17 @@
package ca.uhn.fhir.rest.server;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.client.MyPatientWithExtensions;
import ca.uhn.fhir.test.utilities.JettyUtil;
import ca.uhn.fhir.util.TestUtil;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.CloseableHttpResponse;
@ -40,18 +39,18 @@ import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.client.MyPatientWithExtensions;
import ca.uhn.fhir.test.utilities.JettyUtil;
import ca.uhn.fhir.util.TestUtil;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
public class ServerMimetypeR4Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerMimetypeR4Test.class);
@ -406,45 +405,16 @@ public class ServerMimetypeR4Test {
return retVal;
}
@AfterClass
public static void afterClassClearContext() throws Exception {
JettyUtil.closeServer(ourServer);
TestUtil.clearAllStaticFieldsForUnitTest();
}
@BeforeClass
public static void beforeClass() throws Exception {
ourServer = new Server(0);
PatientProvider patientProvider = new PatientProvider();
ServletHandler proxyHandler = new ServletHandler();
ourServlet = new RestfulServer(ourCtx);
ourServlet.setResourceProviders(patientProvider);
ServletHolder servletHolder = new ServletHolder(ourServlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler);
JettyUtil.startServer(ourServer);
ourPort = JettyUtil.getPortForStartedServer(ourServer);
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setConnectionManager(connectionManager);
ourClient = builder.build();
}
public static class PatientProvider implements IResourceProvider {
@Create()
public MethodOutcome create(@ResourceParam Patient theIdParam) {
OperationOutcome oo = new OperationOutcome();
oo.addIssue().setDiagnostics(theIdParam.getNameFirstRep().getFamily());
theIdParam.setId("1");
theIdParam.getMeta().setVersionId("1");
return new MethodOutcome(new IdType("Patient", "1"), true).setOperationOutcome(oo).setResource(theIdParam);
}
@ -480,4 +450,33 @@ public class ServerMimetypeR4Test {
}
@AfterClass
public static void afterClassClearContext() throws Exception {
JettyUtil.closeServer(ourServer);
TestUtil.clearAllStaticFieldsForUnitTest();
}
@BeforeClass
public static void beforeClass() throws Exception {
ourServer = new Server(0);
PatientProvider patientProvider = new PatientProvider();
ServletHandler proxyHandler = new ServletHandler();
ourServlet = new RestfulServer(ourCtx);
ourServlet.setResourceProviders(patientProvider);
ServletHolder servletHolder = new ServletHolder(ourServlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler);
JettyUtil.startServer(ourServer);
ourPort = JettyUtil.getPortForStartedServer(ourServer);
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setConnectionManager(connectionManager);
ourClient = builder.build();
}
}

View File

@ -308,7 +308,7 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>@{argLine} -Dfile.encoding=UTF-8 -Xmx712m</argLine>
<argLine>@{argLine} ${surefire_jvm_args}</argLine>
</configuration>
</plugin>
<plugin>

View File

@ -81,7 +81,7 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>@{argLine} -Dfile.encoding=UTF-8 -Xmx712m</argLine>
<argLine>@{argLine} ${surefire_jvm_args}</argLine>
</configuration>
</plugin>
<plugin>

View File

@ -0,0 +1,55 @@
package ca.uhn.fhir.test.utilities.server;
/*-
* #%L
* HAPI FHIR Test Utilities
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
public class ResourceProviderRule implements TestRule {
private final RestfulServerRule myRestfulServerRule;
private Object myProvider;
/**
* Constructor
*/
public ResourceProviderRule(RestfulServerRule theRestfulServerRule, Object theProvider) {
myRestfulServerRule = theRestfulServerRule;
myProvider = theProvider;
}
@Override
public Statement apply(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
myRestfulServerRule.getRestfulServer().registerProvider(myProvider);
try {
base.evaluate();
} finally {
myRestfulServerRule.getRestfulServer().unregisterProvider(myProvider);
}
}
};
}
}

View File

@ -112,4 +112,8 @@ public class RestfulServerRule implements TestRule {
public RestfulServer getRestfulServer() {
return myServlet;
}
public int getPort() {
return myPort;
}
}

View File

@ -540,7 +540,7 @@ function updateURLParameter(url, param, paramVal){
var temp = "";
if (additionalURL) {
tempArray = additionalURL.split("&");
for (i=0; i<tempArray.length; i++){
for (var i=0; i<tempArray.length; i++){
if(tempArray[i].split('=')[0] !== param){
newAdditionalURL += temp + tempArray[i];
temp = "&";

View File

@ -275,7 +275,7 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>@{argLine} -Dfile.encoding=UTF-8 -Xmx712m</argLine>
<argLine>@{argLine} ${surefire_jvm_args}</argLine>
</configuration>
</plugin>
<plugin>

37
pom.xml
View File

@ -582,9 +582,11 @@
<properties>
<fhir_core_version>4.1.0</fhir_core_version>
<fhir_core_version>4.1.7-SNAPSHOT</fhir_core_version>
<ucum_version>1.0.2</ucum_version>
<surefire_jvm_args>-Dfile.encoding=UTF-8 -Xmx1024m</surefire_jvm_args>
<!-- configure timestamp in MANIFEST.MF for maven-war-provider -->
<maven.build.timestamp.format>yyyy-MM-dd'T'HH:mm:ss'Z'</maven.build.timestamp.format>
@ -615,7 +617,7 @@
<jaxb_runtime_version>2.3.1</jaxb_runtime_version>
<jersey_version>2.25.1</jersey_version>
<!-- 9.4.17 seems to have issues -->
<jetty_version>9.4.14.v20181114</jetty_version>
<jetty_version>9.4.23.v20191118</jetty_version>
<jsr305_version>3.0.2</jsr305_version>
<flyway_version>6.0.8</flyway_version>
<!--<hibernate_version>5.2.10.Final</hibernate_version>-->
@ -712,7 +714,7 @@
<dependency>
<groupId>com.icegreen</groupId>
<artifactId>greenmail</artifactId>
<version>1.5.10</version>
<version>1.5.11</version>
</dependency>
<dependency>
<groupId>com.icegreen</groupId>
@ -1663,9 +1665,9 @@
<configuration>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
<runOrder>random</runOrder>
<argLine>-Dfile.encoding=UTF-8 -Xmx1024m</argLine>
<argLine>@{argLine} ${surefire_jvm_args}</argLine>
<forkCount>1.0C</forkCount>
<trimStackTrace>false</trimStackTrace>
<trimStackTrace>false</trimStackTrace>
</configuration>
</plugin>
<plugin>
@ -2494,6 +2496,31 @@
<modules>
<module>hapi-fhir-jacoco</module>
</modules>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<configuration>
<dumpOnExit>true</dumpOnExit>
</configuration>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>CI</id>
<properties>
<surefire_jvm_args>-Dfile.encoding=UTF-8 -Xmx2048m -XX:TieredStopAtLevel=1 -XX:+UseParallelGC -Xverify:none -Dfile.encoding=UTF-8 -Xss128M -XX:MetaspaceSize=512M -XX:MaxMetaspaceSize=2048M</surefire_jvm_args>
</properties>
</profile>
<profile>
<id>NOPARALLEL</id>

View File

@ -6,7 +6,48 @@
<title>HAPI FHIR Changelog</title>
</properties>
<body>
<release version="4.2.0" date="2019-02-01" description="K">
<release version="4.2.0" date="TBD">
<action type="add">
The version of a few dependencies have been bumped to the
latest versions (dependent HAPI modules listed in brackets):
<![CDATA[
<ul>
<li>Jetty (CLI): 9.4.14.v20181114 -&gt; 9.4.23.v20191118</li>
</ul>
]]>
</action>
<action type="fix" issue="1583">
As of FHIR R4, some fields that were previously of type reference are now of type canonical.
One example is QuestionnaireResponse.questionnaire. Technically this means that this field
should no longer contain a relative reference, but as they are sometimes used that way, HAPI
FHIR will now try to be permissive and will index relative link canonical fields
such as (Questionnaire/123) as though it actually was a local relative link. Thanks to
Dean Atchley for reporting and providing a test case!
</action>
<action type="fix">
ValueSet PreCalculation did not successfully expand valuesets when Lucene was not enabled
in the JPA server. This has been corrected.
</action>
<action type="change">
When parsing Bundle resources containing other resources, XML/JSON parsers have an option called
"override resource ID with bundle entry fullUrl". This option previously caused any value
found in Bundle.entry.fullUrl to override any value found in
Bundle.entry.resource.id (meaning that the parsed resource would take its ID from
the fullUrl even if that ID disagreed with the ID found in the resource itself. As of
HAPI FHIR 4.1.0 the value in Bundle.entry.fullUrl will only be used to set the parsed resource
ID if the resource has no ID present.
</action>
<action type="add">
Chained searches using the _has search parameter as the chain value are now supported by
the JPA server.
</action>
<action type="change">
Changed database migration to use flyway. This adds a new table called flyway_schema_history that records all
database migration tasks that have already been applied. The hapi-fhir-cli migrate tool has been changed
to use flyway. Learn more about flyway on https://flywaydb.org/.
</action>
</release>
<release version="4.1.0" date="2019-11-13" description="Jitterbug">
<action type="add">
The version of a few dependencies have been bumped to the
latest versions (dependent HAPI modules listed in brackets):
@ -33,13 +74,6 @@
format. Thanks to Raul Estrada for the pull request!
</action>
-->
<action type="change">
Changed database migration to use flyway. This adds a new table called flyway_schema_history that records all
database migration tasks that have already been applied. The hapi-fhir-cli migrate tool has been changed
to use flyway. Learn more about flyway on https://flywaydb.org/.
</action>
</release>
<release version="4.1.0" date="2019-11-13" description="Jitterbug">
<action type="add">
<![CDATA[
<b>New Feature</b>: