More test coverage

This commit is contained in:
jamesagnew 2016-06-18 13:32:45 -04:00
parent b3d8d453de
commit a7cbb5c022
15 changed files with 404 additions and 63 deletions

View File

@ -721,7 +721,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
protected IBaseResource parseResourceBody(String theResourceBody) { protected IBaseResource parseResourceBody(String theResourceBody) {
EncodingEnum encoding = MethodUtil.detectEncodingNoDefault(theResourceBody); EncodingEnum encoding = MethodUtil.detectEncodingNoDefault(theResourceBody);
if (encoding == null) { if (encoding == null) {
throw new InvalidRequestException("FHIR client can't determine resource encoding"); throw new IllegalArgumentException(myContext.getLocalizer().getMessage(GenericClient.class, "cantDetermineRequestType"));
} }
return encoding.newParser(myContext).parseResource(theResourceBody); return encoding.newParser(myContext).parseResource(theResourceBody);
} }
@ -2220,7 +2220,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
myRawBundle = theBundle; myRawBundle = theBundle;
myRawBundleEncoding = MethodUtil.detectEncodingNoDefault(myRawBundle); myRawBundleEncoding = MethodUtil.detectEncodingNoDefault(myRawBundle);
if (myRawBundleEncoding == null) { if (myRawBundleEncoding == null) {
throw new IllegalArgumentException("Can not determine encoding of raw resource body"); throw new IllegalArgumentException(myContext.getLocalizer().getMessage(GenericClient.class, "cantDetermineRequestType"));
} }
} }
@ -2431,7 +2431,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
EncodingEnum enc = MethodUtil.detectEncodingNoDefault(theResourceRaw); EncodingEnum enc = MethodUtil.detectEncodingNoDefault(theResourceRaw);
if (enc == null) { if (enc == null) {
throw new IllegalArgumentException("Could not detect encoding (XML/JSON) in string. Is this a valid FHIR resource?"); throw new IllegalArgumentException(myContext.getLocalizer().getMessage(GenericClient.class, "cantDetermineRequestType"));
} }
switch (enc) { switch (enc) {
case XML: case XML:

View File

@ -25,6 +25,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseBinary; import org.hl7.fhir.instance.model.api.IBaseBinary;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
@ -200,9 +201,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
if (myParams != null) { if (myParams != null) {
return httpClient.createParamRequest(getContext(), myParams, encoding); return httpClient.createParamRequest(getContext(), myParams, encoding);
} else { } else {
if (encoding == null) { encoding = ObjectUtils.defaultIfNull(encoding, EncodingEnum.XML);
encoding = EncodingEnum.XML;
}
String contents = encodeContents(thePrettyPrint, encoding); String contents = encodeContents(thePrettyPrint, encoding);
String contentType = getContentType(encoding); String contentType = getContentType(encoding);
return httpClient.createByteRequest(getContext(), contents, contentType, encoding); return httpClient.createByteRequest(getContext(), contents, contentType, encoding);

View File

@ -36,6 +36,7 @@ import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.instance.model.api.IPrimitiveType;
@ -45,7 +46,6 @@ import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.Include; import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
import ca.uhn.fhir.model.valueset.BundleTypeEnum; import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.MethodOutcome;
@ -232,7 +232,7 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
return resource; return resource;
case METHOD_OUTCOME: case METHOD_OUTCOME:
MethodOutcome retVal = new MethodOutcome(); MethodOutcome retVal = new MethodOutcome();
retVal.setOperationOutcome((BaseOperationOutcome) resource); retVal.setOperationOutcome((IBaseOperationOutcome) resource);
return retVal; return retVal;
} }
break; break;

View File

@ -6,10 +6,8 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.IOException; import java.io.IOException;
import java.io.PushbackReader; import java.io.PushbackReader;
import java.io.Reader; import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -23,6 +21,7 @@ import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseMetaType; import org.hl7.fhir.instance.model.api.IBaseMetaType;
@ -46,7 +45,6 @@ import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.api.annotation.Description; import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.annotation.At; import ca.uhn.fhir.rest.annotation.At;
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam; import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
@ -89,7 +87,9 @@ import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.IDynamicSearchResourceProvider; import ca.uhn.fhir.rest.server.IDynamicSearchResourceProvider;
import ca.uhn.fhir.rest.server.SearchParameterMap; import ca.uhn.fhir.rest.server.SearchParameterMap;
import ca.uhn.fhir.util.DateUtils; import ca.uhn.fhir.util.DateUtils;
import ca.uhn.fhir.util.ParametersUtil;
import ca.uhn.fhir.util.ReflectionUtil; import ca.uhn.fhir.util.ReflectionUtil;
import ca.uhn.fhir.util.UrlUtil;
/* /*
* #%L * #%L
@ -113,6 +113,12 @@ import ca.uhn.fhir.util.ReflectionUtil;
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public class MethodUtil { public class MethodUtil {
/** Non instantiable */
private MethodUtil() {
// nothing
}
private static final String LABEL = "label=\""; private static final String LABEL = "label=\"";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(MethodUtil.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(MethodUtil.class);
@ -132,19 +138,14 @@ public class MethodUtil {
} }
public static IIdType convertIdToType(IIdType value, Class<? extends IIdType> idParamType) { @SuppressWarnings("unchecked")
if (value != null && !idParamType.isAssignableFrom(value.getClass())) { public static <T extends IIdType> T convertIdToType(IIdType value, Class<T> theIdParamType) {
try { if (value != null && !theIdParamType.isAssignableFrom(value.getClass())) {
IIdType newValue = idParamType.newInstance(); IIdType newValue = ReflectionUtil.newInstance(theIdParamType);
newValue.setValue(value.getValue()); newValue.setValue(value.getValue());
value = newValue; value = newValue;
} catch (InstantiationException e) {
throw new ConfigurationException("Failed to instantiate " + idParamType, e);
} catch (IllegalAccessException e) {
throw new ConfigurationException("Failed to instantiate " + idParamType, e);
}
} }
return value; return (T) value;
} }
public static HttpGetClientInvocation createConformanceInvocation(FhirContext theContext) { public static HttpGetClientInvocation createConformanceInvocation(FhirContext theContext) {
@ -212,13 +213,9 @@ public class MethodUtil {
for (String nextValue : nextEntry.getValue()) { for (String nextValue : nextEntry.getValue()) {
b.append(haveQuestionMark ? '&' : '?'); b.append(haveQuestionMark ? '&' : '?');
haveQuestionMark = true; haveQuestionMark = true;
try { b.append(UrlUtil.escape(nextEntry.getKey()));
b.append(URLEncoder.encode(nextEntry.getKey(), "UTF-8")); b.append('=');
b.append('='); b.append(UrlUtil.escape(nextValue));
b.append(URLEncoder.encode(nextValue, "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new ConfigurationException("UTF-8 not supported on this platform");
}
} }
} }
@ -287,9 +284,7 @@ public class MethodUtil {
public static EncodingEnum detectEncoding(String theBody) { public static EncodingEnum detectEncoding(String theBody) {
EncodingEnum retVal = detectEncodingNoDefault(theBody); EncodingEnum retVal = detectEncodingNoDefault(theBody);
if (retVal == null) { retVal = ObjectUtils.defaultIfNull(retVal, EncodingEnum.XML);
retVal = EncodingEnum.XML;
}
return retVal; return retVal;
} }
@ -321,10 +316,6 @@ public class MethodUtil {
} }
} }
public static Integer findConditionalOperationParameterIndex(Method theMethod) {
return MethodUtil.findParamAnnotationIndex(theMethod, ConditionalUrlParam.class);
}
public static Integer findIdParameterIndex(Method theMethod, FhirContext theContext) { public static Integer findIdParameterIndex(Method theMethod, FhirContext theContext) {
Integer index = MethodUtil.findParamAnnotationIndex(theMethod, IdParam.class); Integer index = MethodUtil.findParamAnnotationIndex(theMethod, IdParam.class);
if (index != null) { if (index != null) {
@ -365,7 +356,7 @@ public class MethodUtil {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static List<IParameter> getResourceParameters(FhirContext theContext, Method theMethod, Object theProvider, RestOperationTypeEnum theRestfulOperationTypeEnum) { 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<IParameter>();
Class<?>[] parameterTypes = theMethod.getParameterTypes(); Class<?>[] parameterTypes = theMethod.getParameterTypes();
@ -514,7 +505,7 @@ public class MethodUtil {
@Override @Override
public Object outgoingClient(Object theObject) { public Object outgoingClient(Object theObject) {
return new StringDt(((ValidationModeEnum)theObject).getCode()); return ParametersUtil.createString(theContext, ((ValidationModeEnum)theObject).getCode());
} }
}); });
} else if (nextAnnotation instanceof Validate.Profile) { } else if (nextAnnotation instanceof Validate.Profile) {
@ -529,7 +520,7 @@ public class MethodUtil {
@Override @Override
public Object outgoingClient(Object theObject) { public Object outgoingClient(Object theObject) {
return new StringDt(theObject.toString()); return ParametersUtil.createString(theContext, theObject.toString());
} }
}); });
} else { } else {

View File

@ -10,6 +10,7 @@ ca.uhn.fhir.context.RuntimeResourceDefinition.nonInstantiableType=Resource type
ca.uhn.fhir.rest.client.BaseClient.ioExceptionDuringOperation=Encountered IOException when performing {0} to URL {1} - {2} ca.uhn.fhir.rest.client.BaseClient.ioExceptionDuringOperation=Encountered IOException when performing {0} to URL {1} - {2}
ca.uhn.fhir.rest.client.BaseClient.failedToParseResponse=Failed to parse response from server when performing {0} to URL {1} - {2} ca.uhn.fhir.rest.client.BaseClient.failedToParseResponse=Failed to parse response from server when performing {0} to URL {1} - {2}
ca.uhn.fhir.rest.client.GenericClient.cantDetermineRequestType=Unable to determing encoding of request (body does not appear to be valid XML or JSON)
ca.uhn.fhir.rest.client.GenericClient.noPagingLinkFoundInBundle=Can not perform paging operation because no link was found in Bundle with relation "{0}" ca.uhn.fhir.rest.client.GenericClient.noPagingLinkFoundInBundle=Can not perform paging operation because no link was found in Bundle with relation "{0}"
ca.uhn.fhir.rest.client.GenericClient.noVersionIdForVread=No version specified in URL for 'vread' operation: {0} ca.uhn.fhir.rest.client.GenericClient.noVersionIdForVread=No version specified in URL for 'vread' operation: {0}
ca.uhn.fhir.rest.client.GenericClient.incompleteUriForRead=The given URI is not an absolute URL and is not usable for this operation: {0} ca.uhn.fhir.rest.client.GenericClient.incompleteUriForRead=The given URI is not an absolute URL and is not usable for this operation: {0}

View File

@ -51,8 +51,13 @@ public class DaoConfig {
// *** // ***
// update setter javadoc if default changes // update setter javadoc if default changes
// *** // ***
private int myDeferIndexingForCodesystemsOfSize = 100;
// ***
// update setter javadoc if default changes
// ***
private long myExpireSearchResultsAfterMillis = DateUtils.MILLIS_PER_HOUR; private long myExpireSearchResultsAfterMillis = DateUtils.MILLIS_PER_HOUR;
private int myHardSearchLimit = 1000; private int myHardSearchLimit = 1000;
private int myHardTagListLimit = 1000; private int myHardTagListLimit = 1000;
private int myIncludeLimit = 2000; private int myIncludeLimit = 2000;
@ -61,24 +66,36 @@ public class DaoConfig {
// update setter javadoc if default changes // update setter javadoc if default changes
// *** // ***
private boolean myIndexContainedResources = true; private boolean myIndexContainedResources = true;
private List<IServerInterceptor> myInterceptors; private List<IServerInterceptor> myInterceptors;
// *** // ***
// update setter javadoc if default changes // update setter javadoc if default changes
// *** // ***
private int myMaximumExpansionSize = 5000; private int myMaximumExpansionSize = 5000;
private ResourceEncodingEnum myResourceEncoding = ResourceEncodingEnum.JSONC; private ResourceEncodingEnum myResourceEncoding = ResourceEncodingEnum.JSONC;
private boolean mySchedulingDisabled; private boolean mySchedulingDisabled;
private boolean mySubscriptionEnabled;
private long mySubscriptionPollDelay = 1000;
private Long mySubscriptionPurgeInactiveAfterMillis; private boolean mySubscriptionEnabled;
private Set<String> myTreatBaseUrlsAsLocal = new HashSet<String>();
private long mySubscriptionPollDelay = 1000;
private Long mySubscriptionPurgeInactiveAfterMillis;
private Set<String> myTreatBaseUrlsAsLocal = new HashSet<String>();
/**
* When a code system is added that contains more than this number of codes,
* the code system will be indexed later in an incremental process in order to
* avoid overwhelming Lucene with a huge number of codes in a single operation.
* <p>
* Defaults to 100
* </p>
*/
public int getDeferIndexingForCodesystemsOfSize() {
return myDeferIndexingForCodesystemsOfSize;
}
/** /**
* Sets the number of milliseconds that search results for a given client search * Sets the number of milliseconds that search results for a given client search
* should be preserved before being purged from the database. * should be preserved before being purged from the database.
@ -117,6 +134,7 @@ public class DaoConfig {
} }
return myInterceptors; return myInterceptors;
} }
/** /**
* See {@link #setMaximumExpansionSize(int)} * See {@link #setMaximumExpansionSize(int)}
*/ */
@ -180,7 +198,6 @@ public class DaoConfig {
public boolean isAllowInlineMatchUrlReferences() { public boolean isAllowInlineMatchUrlReferences() {
return myAllowInlineMatchUrlReferences; return myAllowInlineMatchUrlReferences;
} }
public boolean isAllowMultipleDelete() { public boolean isAllowMultipleDelete() {
return myAllowMultipleDelete; return myAllowMultipleDelete;
} }
@ -251,6 +268,18 @@ public class DaoConfig {
myAllowMultipleDelete = theAllowMultipleDelete; myAllowMultipleDelete = theAllowMultipleDelete;
} }
/**
* When a code system is added that contains more than this number of codes,
* the code system will be indexed later in an incremental process in order to
* avoid overwhelming Lucene with a huge number of codes in a single operation.
* <p>
* Defaults to 100
* </p>
*/
public void setDeferIndexingForCodesystemsOfSize(int theDeferIndexingForCodesystemsOfSize) {
myDeferIndexingForCodesystemsOfSize = theDeferIndexingForCodesystemsOfSize;
}
/** /**
* Sets the number of milliseconds that search results for a given client search * Sets the number of milliseconds that search results for a given client search
* should be preserved before being purged from the database. * should be preserved before being purged from the database.

View File

@ -71,12 +71,11 @@ import ca.uhn.fhir.jpa.search.DeferConceptIndexingInterceptor;
//@formatter:on //@formatter:on
public class TermConcept implements Serializable { public class TermConcept implements Serializable {
private static final int MAX_DESC_LENGTH = 400; private static final int MAX_DESC_LENGTH = 400;
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@OneToMany(fetch=FetchType.LAZY, mappedBy="myParent") @OneToMany(fetch=FetchType.LAZY, mappedBy="myParent")
private Collection<TermConceptParentChildLink> myChildren; private Collection<TermConceptParentChildLink> myChildren;
@Column(name="CODE", length=100, nullable=false) @Column(name="CODE", length=100, nullable=false)
@Fields({ @Fields({
@Field(name = "myCode", index = org.hibernate.search.annotations.Index.YES, store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = "exactAnalyzer")), @Field(name = "myCode", index = org.hibernate.search.annotations.Index.YES, store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = "exactAnalyzer")),
@ -86,7 +85,7 @@ public class TermConcept implements Serializable {
@ManyToOne() @ManyToOne()
@JoinColumn(name="CODESYSTEM_PID", referencedColumnName="PID", foreignKey=@ForeignKey(name="FK_CONCEPT_PID_CS_PID")) @JoinColumn(name="CODESYSTEM_PID", referencedColumnName="PID", foreignKey=@ForeignKey(name="FK_CONCEPT_PID_CS_PID"))
private TermCodeSystemVersion myCodeSystem; private TermCodeSystemVersion myCodeSystem;
@Column(name="CODESYSTEM_PID", insertable=false, updatable=false) @Column(name="CODESYSTEM_PID", insertable=false, updatable=false)
@Fields({ @Fields({
@Field(name="myCodeSystemVersionPid") @Field(name="myCodeSystemVersionPid")
@ -103,7 +102,7 @@ public class TermConcept implements Serializable {
}) })
private String myDisplay; private String myDisplay;
//@formatter:on //@formatter:on
@Id() @Id()
@SequenceGenerator(name="SEQ_CONCEPT_PID", sequenceName="SEQ_CONCEPT_PID") @SequenceGenerator(name="SEQ_CONCEPT_PID", sequenceName="SEQ_CONCEPT_PID")
@GeneratedValue(strategy=GenerationType.AUTO, generator="SEQ_CONCEPT_PID") @GeneratedValue(strategy=GenerationType.AUTO, generator="SEQ_CONCEPT_PID")
@ -189,6 +188,10 @@ public class TermConcept implements Serializable {
return myId; return myId;
} }
public Long getIndexStatus() {
return myIndexStatus;
}
public Collection<TermConceptParentChildLink> getParents() { public Collection<TermConceptParentChildLink> getParents() {
if (myParents == null) { if (myParents == null) {
myParents = new ArrayList<TermConceptParentChildLink>(); myParents = new ArrayList<TermConceptParentChildLink>();

View File

@ -1,9 +1,32 @@
package ca.uhn.fhir.jpa.search; package ca.uhn.fhir.jpa.search;
import org.hibernate.search.indexes.interceptor.DontInterceptEntityInterceptor; import org.hibernate.search.indexes.interceptor.EntityIndexingInterceptor;
import org.hibernate.search.indexes.interceptor.IndexingOverride;
public class DeferConceptIndexingInterceptor extends DontInterceptEntityInterceptor import ca.uhn.fhir.jpa.entity.TermConcept;
//implements EntityIndexingInterceptor<TermConcept>
{ public class DeferConceptIndexingInterceptor implements EntityIndexingInterceptor<TermConcept> {
// nothing for now
@Override
public IndexingOverride onAdd(TermConcept theEntity) {
if (theEntity.getIndexStatus() == null) {
return IndexingOverride.SKIP;
}
return IndexingOverride.APPLY_DEFAULT;
}
@Override
public IndexingOverride onUpdate(TermConcept theEntity) {
return onAdd(theEntity);
}
@Override
public IndexingOverride onDelete(TermConcept theEntity) {
return IndexingOverride.APPLY_DEFAULT;
}
@Override
public IndexingOverride onCollectionUpdate(TermConcept theEntity) {
return IndexingOverride.APPLY_DEFAULT;
}
} }

View File

@ -216,7 +216,9 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
} }
theConcept.setCodeSystem(theCodeSystem); theConcept.setCodeSystem(theCodeSystem);
theConcept.setIndexStatus(BaseHapiFhirDao.INDEX_STATUS_INDEXED); if (theTotalConcepts < myDaoConfig.getDeferIndexingForCodesystemsOfSize()) {
theConcept.setIndexStatus(BaseHapiFhirDao.INDEX_STATUS_INDEXED);
}
myConceptDao.save(theConcept); myConceptDao.save(theConcept);
for (TermConceptParentChildLink next : theConcept.getChildren()) { for (TermConceptParentChildLink next : theConcept.getChildren()) {

View File

@ -174,7 +174,7 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvc implements I
} else if (nextFilter.getOp() == FilterOperator.ISA) { } else if (nextFilter.getOp() == FilterOperator.ISA) {
if (isNotBlank(nextFilter.getValue())) { if (isNotBlank(nextFilter.getValue())) {
TermConcept code = super.findCode(system, nextFilter.getValue()); TermConcept code = super.findCode(system, nextFilter.getValue());
bool.must(qb.keyword().onField("myParentPids").matching(code.getId()).createQuery()); bool.must(qb.keyword().onField("myParentPids").matching("" + code.getId()).createQuery());
} }
} else { } else {
throw new InvalidRequestException("Unknown filter property[" + nextFilter + "] + op[" + nextFilter.getOpElement().getValueAsString() + "]"); throw new InvalidRequestException("Unknown filter property[" + nextFilter + "] + op[" + nextFilter.getOpElement().getValueAsString() + "]");

View File

@ -9,7 +9,6 @@ import static org.junit.Assert.fail;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.TreeSet;
import org.hl7.fhir.dstu3.model.AuditEvent; import org.hl7.fhir.dstu3.model.AuditEvent;
import org.hl7.fhir.dstu3.model.CodeSystem; import org.hl7.fhir.dstu3.model.CodeSystem;
@ -22,11 +21,13 @@ import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.dstu3.model.ValueSet.FilterOperator; import org.hl7.fhir.dstu3.model.ValueSet.FilterOperator;
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent; import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.After;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.SearchParameterMap; import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.entity.ResourceTable; import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion; import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
@ -339,6 +340,25 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
assertEquals(URL_MY_CODE_SYSTEM, result.getExpansion().getContains().get(idx).getSystem()); assertEquals(URL_MY_CODE_SYSTEM, result.getExpansion().getContains().get(idx).getSystem());
} }
@Test
public void testIndexingIsDeferredForLargeCodeSystems() {
myDaoConfig.setDeferIndexingForCodesystemsOfSize(1);
createExternalCsAndLocalVs();
ValueSet vs = new ValueSet();
ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
include.addFilter().setProperty("display").setOp(FilterOperator.ISA).setValue("ParentA");
ValueSet result = myValueSetDao.expand(vs, null);
String encoded = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result);
ourLog.info(encoded);
}
@Test @Test
public void testExpandWithExcludeInExternalValueSet() { public void testExpandWithExcludeInExternalValueSet() {
createExternalCsAndLocalVs(); createExternalCsAndLocalVs();
@ -486,6 +506,11 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
public void before() { public void before() {
myDaoConfig.setMaximumExpansionSize(5000); myDaoConfig.setMaximumExpansionSize(5000);
} }
@After
public void after() {
myDaoConfig.setDeferIndexingForCodesystemsOfSize(new DaoConfig().getDeferIndexingForCodesystemsOfSize());
}
@Test @Test
public void testSearchCodeBelowLocalCodesystem() { public void testSearchCodeBelowLocalCodesystem() {

View File

@ -18,6 +18,7 @@ import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam; import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.annotation.ResourceParam; import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Update; 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.api.MethodOutcome;
import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
@ -62,6 +63,51 @@ public class ServerInvalidDefinitionDstu2Test {
} }
} }
@Test
public void testWrongResourceType() {
RestfulServer srv = new RestfulServer(ourCtx);
srv.setFhirContext(ourCtx);
srv.setResourceProviders(new UpdateWithWrongResourceType());
try {
srv.init();
fail();
} 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[]"));
}
}
@Test
public void testWrongValidateModeType() {
RestfulServer srv = new RestfulServer(ourCtx);
srv.setFhirContext(ourCtx);
srv.setResourceProviders(new ValidateWithWrongModeType());
try {
srv.init();
fail();
} catch (ServletException e) {
assertThat(e.getCause().toString(), StringContains.containsString("ConfigurationException"));
assertThat(e.getCause().toString(), StringContains.containsString("Parameter annotated with @Validate.Mode must be of type ca.uhn.fhir.rest.api.ValidationModeEnum"));
}
}
@Test
public void testWrongValidateProfileType() {
RestfulServer srv = new RestfulServer(ourCtx);
srv.setFhirContext(ourCtx);
srv.setResourceProviders(new ValidateWithWrongProfileType());
try {
srv.init();
fail();
} catch (ServletException e) {
assertThat(e.getCause().toString(), StringContains.containsString("ConfigurationException"));
assertThat(e.getCause().toString(), StringContains.containsString("Parameter annotated with @Validate.Profile must be of type java.lang.String"));
}
}
public static class OperationReturningOldBundleProvider implements IResourceProvider { public static class OperationReturningOldBundleProvider implements IResourceProvider {
@Override @Override
@ -90,4 +136,46 @@ public class ServerInvalidDefinitionDstu2Test {
} }
public static class UpdateWithWrongResourceType implements IResourceProvider {
@Override
public Class<? extends IBaseResource> getResourceType() {
return Patient.class;
}
@Update
public MethodOutcome update(@ResourceParam Integer theParam2) {
return null;
}
}
public static class ValidateWithWrongModeType implements IResourceProvider {
@Override
public Class<? extends IBaseResource> getResourceType() {
return Patient.class;
}
@Validate
public MethodOutcome update(@ResourceParam Patient thePatient, @Validate.Mode Integer theParam2) {
return null;
}
}
public static class ValidateWithWrongProfileType implements IResourceProvider {
@Override
public Class<? extends IBaseResource> getResourceType() {
return Patient.class;
}
@Validate
public MethodOutcome update(@ResourceParam Patient thePatient, @Validate.Profile Integer theParam2) {
return null;
}
}
} }

View File

@ -1147,6 +1147,45 @@ public class GenericClientDstu3Test {
//@formatter:on //@formatter:on
} }
@Test
public void testTransactionWithInvalidBody() throws Exception {
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
// Transaction
try {
client.transaction().withBundle("FOO");
fail();
} catch (IllegalArgumentException e) {
assertEquals("Unable to determing encoding of request (body does not appear to be valid XML or JSON)", e.getMessage());
}
// Create
try {
client.create().resource("FOO").execute();
fail();
} catch (IllegalArgumentException e) {
assertEquals("Unable to determing encoding of request (body does not appear to be valid XML or JSON)", e.getMessage());
}
// Update
try {
client.update().resource("FOO").execute();
fail();
} catch (IllegalArgumentException e) {
assertEquals("Unable to determing encoding of request (body does not appear to be valid XML or JSON)", e.getMessage());
}
// Validate
try {
client.validate().resource("FOO").execute();
fail();
} catch (IllegalArgumentException e) {
assertEquals("Unable to determing encoding of request (body does not appear to be valid XML or JSON)", e.getMessage());
}
}
@Test @Test
public void testUpdateById() throws Exception { public void testUpdateById() throws Exception {
IParser p = ourCtx.newXmlParser(); IParser p = ourCtx.newXmlParser();

View File

@ -0,0 +1,122 @@
package ca.uhn.fhir.rest.client;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.Charset;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.ReaderInputStream;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicStatusLine;
import org.hl7.fhir.dstu3.model.OperationOutcome;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Validate;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.ValidationModeEnum;
import ca.uhn.fhir.rest.client.api.IRestfulClient;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.util.TestUtil;
public class NonGenericClientDstu3Test {
private static FhirContext ourCtx;
private HttpClient myHttpClient;
private HttpResponse myHttpResponse;
@Before
public void before() {
myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
ourCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
System.setProperty(BaseClient.HAPI_CLIENT_KEEPRESPONSES, "true");
}
private String extractBodyAsString(ArgumentCaptor<HttpUriRequest> capt, int theIdx) throws IOException {
String body = IOUtils.toString(((HttpEntityEnclosingRequestBase) capt.getAllValues().get(theIdx)).getEntity().getContent(), "UTF-8");
return body;
}
@Test
public void testValidateResourceOnly() throws Exception {
IParser p = ourCtx.newXmlParser();
OperationOutcome conf = new OperationOutcome();
conf.getText().setDivAsString("OK!");
final String respString = p.encodeResourceToString(conf);
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().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
@Override
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8"));
}
});
IClient client = ourCtx.newRestfulClient(IClient.class, "http://example.com/fhir");
Patient patient = new Patient();
patient.addName().addFamily("FAM");
int idx = 0;
MethodOutcome outcome = client.validate(patient, null, null);
String resp = ourCtx.newXmlParser().encodeResourceToString(outcome.getOperationOutcome());
assertEquals("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><text><div xmlns=\"http://www.w3.org/1999/xhtml\">OK!</div></text></OperationOutcome>", resp);
assertEquals("http://example.com/fhir/$validate", capt.getAllValues().get(idx).getURI().toString());
String request = extractBodyAsString(capt,idx);
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><family value=\"FAM\"/></name></Patient></resource></parameter></Parameters>", request);
idx = 1;
outcome = client.validate(patient, ValidationModeEnum.CREATE, "http://foo");
resp = ourCtx.newXmlParser().encodeResourceToString(outcome.getOperationOutcome());
assertEquals("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><text><div xmlns=\"http://www.w3.org/1999/xhtml\">OK!</div></text></OperationOutcome>", resp);
assertEquals("http://example.com/fhir/$validate", capt.getAllValues().get(idx).getURI().toString());
request = extractBodyAsString(capt,idx);
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><family value=\"FAM\"/></name></Patient></resource></parameter><parameter><name value=\"mode\"/><valueString value=\"create\"/></parameter><parameter><name value=\"profile\"/><valueString value=\"http://foo\"/></parameter></Parameters>", request);
}
private interface IClient extends IRestfulClient {
@Validate
MethodOutcome validate(@ResourceParam IBaseResource theResource, @Validate.Mode ValidationModeEnum theMode, @Validate.Profile String theProfile);
}
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
}
@BeforeClass
public static void beforeClass() {
ourCtx = FhirContext.forDstu3();
}
}

View File

@ -0,0 +1,19 @@
package ca.uhn.fhir.rest.method;
import static org.junit.Assert.*;
import org.hl7.fhir.dstu3.model.IdType;
import org.junit.Test;
import ca.uhn.fhir.model.primitive.IdDt;
public class MethodUtilTest {
@Test
public void testConvertIdToType() {
IdDt id = new IdDt("Patient/123");
IdType id2 = MethodUtil.convertIdToType(id, IdType.class);
assertEquals("Patient/123", id2.getValue());
}
}