mirror of
https://github.com/hapifhir/hapi-fhir.git
synced 2025-03-09 14:33:32 +00:00
Merge branch 'master' into hapi3_refactor
This commit is contained in:
commit
b405e51773
@ -99,7 +99,11 @@ public abstract class BaseRuntimeElementCompositeDefinition<T extends IBase> ext
|
||||
if (childOrder != null) {
|
||||
forcedOrder = new HashMap<String, Integer>();
|
||||
for (int i = 0; i < childOrder.names().length; i++) {
|
||||
forcedOrder.put(childOrder.names()[i], i);
|
||||
String nextName = childOrder.names()[i];
|
||||
if (nextName.endsWith("[x]")) {
|
||||
nextName = nextName.substring(0, nextName.length() - 3);
|
||||
}
|
||||
forcedOrder.put(nextName, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ package ca.uhn.fhir.rest.param;
|
||||
* 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
|
||||
* 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,
|
||||
@ -44,8 +44,13 @@ public abstract class BaseParamWithPrefix<T extends BaseParam> extends BaseParam
|
||||
String extractPrefixAndReturnRest(String theString) {
|
||||
int offset = 0;
|
||||
while (true) {
|
||||
if (theString.length() == offset || Character.isDigit(theString.charAt(offset))) {
|
||||
if (theString.length() == offset) {
|
||||
break;
|
||||
} else {
|
||||
char nextChar = theString.charAt(offset);
|
||||
if (nextChar == '-' || Character.isDigit(nextChar)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
@ -60,7 +65,7 @@ public abstract class BaseParamWithPrefix<T extends BaseParam> extends BaseParam
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getPrefix() instead}
|
||||
* @deprecated Use {@link #getPrefix()} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public QuantityCompararatorEnum getComparator() {
|
||||
@ -68,7 +73,7 @@ public abstract class BaseParamWithPrefix<T extends BaseParam> extends BaseParam
|
||||
if (prefix == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return QuantityCompararatorEnum.forCode(prefix.getDstu1Value());
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ package ca.uhn.fhir.util;
|
||||
* 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
|
||||
* 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,
|
||||
@ -41,24 +41,6 @@ import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
*/
|
||||
public class OperationOutcomeUtil {
|
||||
|
||||
// /**
|
||||
// * Add an issue to an OperationOutcome
|
||||
// *
|
||||
// * @param theCtx
|
||||
// * The fhir context
|
||||
// * @param theOperationOutcome
|
||||
// * The OO resource to add to
|
||||
// * @param theSeverity
|
||||
// * The severity (e.g. "error")
|
||||
// * @param theDetails
|
||||
// * The details string
|
||||
// * @param theCode
|
||||
// */
|
||||
// public static void addIssue(FhirContext theCtx, IBaseOperationOutcome theOperationOutcome, String theSeverity, String theDetails, String theCode) {
|
||||
// IBase issue = createIssue(theCtx, theOperationOutcome);
|
||||
// populateDetails(theCtx, issue, theSeverity, theDetails, null, theCode);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Add an issue to an OperationOutcome
|
||||
*
|
||||
@ -67,10 +49,10 @@ public class OperationOutcomeUtil {
|
||||
* @param theOperationOutcome
|
||||
* The OO resource to add to
|
||||
* @param theSeverity
|
||||
* The severity (e.g. "error")
|
||||
* The severity (fatal | error | warning | information)
|
||||
* @param theDetails
|
||||
* The details string
|
||||
* @param theCode
|
||||
* @param theCode
|
||||
*/
|
||||
public static void addIssue(FhirContext theCtx, IBaseOperationOutcome theOperationOutcome, String theSeverity, String theDetails, String theLocation, String theCode) {
|
||||
IBase issue = createIssue(theCtx, theOperationOutcome);
|
||||
@ -150,7 +132,7 @@ public class OperationOutcomeUtil {
|
||||
BaseRuntimeChildDefinition detailsChild;
|
||||
if (theCtx.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
|
||||
detailsChild = issueElement.getChildByName("diagnostics");
|
||||
|
||||
|
||||
BaseRuntimeChildDefinition codeChild = issueElement.getChildByName("code");
|
||||
IPrimitiveType<?> codeElem = (IPrimitiveType<?>) codeChild.getChildByName("code").newInstance(codeChild.getInstanceConstructorArguments());
|
||||
codeElem.setValueAsString(theCode);
|
||||
@ -158,7 +140,7 @@ public class OperationOutcomeUtil {
|
||||
} else {
|
||||
detailsChild = issueElement.getChildByName("details");
|
||||
}
|
||||
|
||||
|
||||
BaseRuntimeElementDefinition<?> stringDef = detailsChild.getChildByName(detailsChild.getElementName());
|
||||
BaseRuntimeChildDefinition severityChild = issueElement.getChildByName("severity");
|
||||
BaseRuntimeChildDefinition locationChild = issueElement.getChildByName("location");
|
||||
|
@ -27,7 +27,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.model.api.IFhirVersion;
|
||||
import ca.uhn.fhir.context.support.IContextValidationSupport;
|
||||
import javassist.Modifier;
|
||||
|
||||
public class ReflectionUtil {
|
||||
@ -153,20 +153,35 @@ public class ReflectionUtil {
|
||||
}
|
||||
|
||||
public static Object newInstanceOfFhirServerType(String theType) {
|
||||
String errorMessage = "Unable to instantiate server framework. Please make sure that hapi-fhir-server library is on your classpath!";
|
||||
String wantedType = "ca.uhn.fhir.rest.api.server.IFhirVersionServer";
|
||||
Object fhirServerVersion = newInstanceOfType(theType, errorMessage, wantedType);
|
||||
return fhirServerVersion;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <EVS_IN, EVS_OUT, SDT, CST, CDCT, IST> ca.uhn.fhir.context.support.IContextValidationSupport<EVS_IN, EVS_OUT, SDT, CST, CDCT, IST> newInstanceOfFhirProfileValidationSupport(
|
||||
String theType) {
|
||||
String errorMessage = "Unable to instantiate validation support! Please make sure that hapi-fhir-validation and the appropriate structures JAR are on your classpath!";
|
||||
String wantedType = "ca.uhn.fhir.context.support.IContextValidationSupport";
|
||||
Object fhirServerVersion = newInstanceOfType(theType, errorMessage, wantedType);
|
||||
return (IContextValidationSupport<EVS_IN, EVS_OUT, SDT, CST, CDCT, IST>) fhirServerVersion;
|
||||
}
|
||||
|
||||
private static Object newInstanceOfType(String theType, String errorMessage, String wantedType) {
|
||||
Object fhirServerVersion = ourFhirServerVersions.get(theType);
|
||||
if (fhirServerVersion == null) {
|
||||
try {
|
||||
Class<?> type = Class.forName(theType);
|
||||
Class<?> serverType = Class.forName("ca.uhn.fhir.rest.api.server.IFhirVersionServer");
|
||||
Class<?> serverType = Class.forName(wantedType);
|
||||
Validate.isTrue(serverType.isAssignableFrom(type));
|
||||
fhirServerVersion = type.newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new ConfigurationException("Unable to instantiate server framework. Please make sure that hapi-fhir-server library is on your classpath!", e);
|
||||
throw new ConfigurationException(errorMessage, e);
|
||||
}
|
||||
|
||||
|
||||
ourFhirServerVersions.put(theType, fhirServerVersion);
|
||||
}
|
||||
|
||||
return fhirServerVersion;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ import org.springframework.web.context.ContextLoader;
|
||||
import org.springframework.web.context.ContextLoaderListener;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.demo.ContextHolder;
|
||||
import ca.uhn.fhir.jpa.demo.FhirServerConfig;
|
||||
import ca.uhn.fhir.jpa.demo.FhirServerConfigDstu3;
|
||||
@ -30,6 +31,7 @@ public class RunServerCommand extends BaseCommand {
|
||||
private static final String OPTION_DISABLE_REFERENTIAL_INTEGRITY = "disable-referential-integrity";
|
||||
private static final String OPTION_LOWMEM = "lowmem";
|
||||
private static final String OPTION_ALLOW_EXTERNAL_REFS = "allow-external-refs";
|
||||
private static final String OPTION_REUSE_SEARCH_RESULTS_MILLIS = "reuse-search-results-milliseconds";
|
||||
private static final int DEFAULT_PORT = 8080;
|
||||
private static final String OPTION_P = "p";
|
||||
|
||||
@ -51,6 +53,10 @@ public class RunServerCommand extends BaseCommand {
|
||||
options.addOption(null, OPTION_LOWMEM, false, "If this flag is set, the server will operate in low memory mode (some features disabled)");
|
||||
options.addOption(null, OPTION_ALLOW_EXTERNAL_REFS, false, "If this flag is set, the server will allow resources to be persisted contaning external resource references");
|
||||
options.addOption(null, OPTION_DISABLE_REFERENTIAL_INTEGRITY, false, "If this flag is set, the server will not enforce referential integrity");
|
||||
|
||||
Long defaultReuseSearchResults = DaoConfig.DEFAULT_REUSE_CACHED_SEARCH_RESULTS_FOR_MILLIS;
|
||||
String defaultReuseSearchResultsStr = defaultReuseSearchResults == null ? "off" : String.valueOf(defaultReuseSearchResults);
|
||||
options.addOption(null, OPTION_REUSE_SEARCH_RESULTS_MILLIS, true, "The time in milliseconds within which the same results will be returned for multiple identical searches, or \"off\" (default is " + defaultReuseSearchResultsStr + ")");
|
||||
return options;
|
||||
}
|
||||
|
||||
@ -58,7 +64,7 @@ public class RunServerCommand extends BaseCommand {
|
||||
try {
|
||||
return Integer.parseInt(theCommandLine.getOptionValue(opt, Integer.toString(defaultPort)));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ParseException("Invalid value '" + theCommandLine.getOptionValue(opt) + " (must be numeric)");
|
||||
throw new ParseException("Invalid value '" + theCommandLine.getOptionValue(opt) + "' (must be numeric)");
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,6 +87,25 @@ public class RunServerCommand extends BaseCommand {
|
||||
ContextHolder.setDisableReferentialIntegrity(true);
|
||||
}
|
||||
|
||||
String reuseSearchResults = theCommandLine.getOptionValue(OPTION_REUSE_SEARCH_RESULTS_MILLIS);
|
||||
if (reuseSearchResults != null) {
|
||||
if (reuseSearchResults.equals("off")) {
|
||||
ourLog.info("Server is configured to not reuse search results");
|
||||
ContextHolder.setReuseCachedSearchResultsForMillis(null);
|
||||
} else {
|
||||
try {
|
||||
long reuseSearchResultsMillis = Long.parseLong(reuseSearchResults);
|
||||
if (reuseSearchResultsMillis < 0) {
|
||||
throw new NumberFormatException("expected a positive integer");
|
||||
}
|
||||
ourLog.info("Server is configured to reuse search results for " + String.valueOf(reuseSearchResultsMillis) + " milliseconds");
|
||||
ContextHolder.setReuseCachedSearchResultsForMillis(reuseSearchResultsMillis);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ParseException("Invalid value '" + reuseSearchResults + "' (must be a positive integer)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ContextHolder.setCtx(getSpecVersionContext(theCommandLine));
|
||||
|
||||
ourLog.info("Preparing HAPI FHIR JPA server on port {}", myPort);
|
||||
|
@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.demo;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
|
||||
public class ContextHolder {
|
||||
@ -11,6 +12,11 @@ public class ContextHolder {
|
||||
private static FhirContext ourCtx;
|
||||
private static boolean ourDisableReferentialIntegrity;
|
||||
private static String ourPath;
|
||||
private static Long ourReuseSearchResultsMillis;
|
||||
|
||||
static {
|
||||
ourReuseSearchResultsMillis = DaoConfig.DEFAULT_REUSE_CACHED_SEARCH_RESULTS_FOR_MILLIS;
|
||||
}
|
||||
|
||||
public static FhirContext getCtx() {
|
||||
Validate.notNull(ourPath, "Context not set");
|
||||
@ -53,4 +59,11 @@ public class ContextHolder {
|
||||
ourDisableReferentialIntegrity = theDisableReferentialIntegrity;
|
||||
}
|
||||
|
||||
public static void setReuseCachedSearchResultsForMillis(Long reuseSearchResultsMillis) {
|
||||
ourReuseSearchResultsMillis = reuseSearchResultsMillis;
|
||||
}
|
||||
|
||||
public static Long getReuseCachedSearchResultsForMillis() {
|
||||
return ourReuseSearchResultsMillis;
|
||||
}
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ public class JpaServerDemo extends RestfulServer {
|
||||
daoConfig.setAllowExternalReferences(ContextHolder.isAllowExternalRefs());
|
||||
daoConfig.setEnforceReferentialIntegrityOnDelete(!ContextHolder.isDisableReferentialIntegrity());
|
||||
daoConfig.setEnforceReferentialIntegrityOnWrite(!ContextHolder.isDisableReferentialIntegrity());
|
||||
|
||||
daoConfig.setReuseCachedSearchResultsForMillis(ContextHolder.getReuseCachedSearchResultsForMillis());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package ca.uhn.fhir.jpa.config.r4;
|
||||
|
||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator;
|
||||
import org.hl7.fhir.r4.hapi.validation.IValidationSupport;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator.BestPracticeWarningLevel;
|
||||
|
||||
/*
|
||||
|
@ -105,6 +105,7 @@ public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2<Subsc
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.NOT_SUPPORTED)
|
||||
@Override
|
||||
public int pollForNewUndeliveredResources() {
|
||||
return pollForNewUndeliveredResources((String) null);
|
||||
|
@ -49,6 +49,7 @@ import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamUriDao;
|
||||
import ca.uhn.fhir.jpa.entity.*;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
||||
import ca.uhn.fhir.jpa.term.VersionIndependentConcept;
|
||||
import ca.uhn.fhir.jpa.util.BaseIterator;
|
||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
||||
import ca.uhn.fhir.model.api.*;
|
||||
import ca.uhn.fhir.model.base.composite.*;
|
||||
@ -1965,7 +1966,7 @@ public class SearchBuilder implements ISearchBuilder {
|
||||
return thePredicates.toArray(new Predicate[thePredicates.size()]);
|
||||
}
|
||||
|
||||
public class IncludesIterator implements Iterator<Long>{
|
||||
public class IncludesIterator extends BaseIterator<Long> implements Iterator<Long>{
|
||||
|
||||
private Iterator<Long> myCurrentIterator;
|
||||
private int myCurrentOffset;
|
||||
@ -2055,7 +2056,7 @@ public class SearchBuilder implements ISearchBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private final class QueryIterator implements Iterator<Long> {
|
||||
private final class QueryIterator extends BaseIterator<Long> implements Iterator<Long> {
|
||||
|
||||
private boolean myFirst = true;
|
||||
private IncludesIterator myIncludesIterator;
|
||||
@ -2175,7 +2176,7 @@ public class SearchBuilder implements ISearchBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
public class ScrollableResultsIterator implements Iterator<Long> {
|
||||
public class ScrollableResultsIterator extends BaseIterator<Long> implements Iterator<Long> {
|
||||
|
||||
private Long myNext;
|
||||
private ScrollableResults myScroll;
|
||||
|
@ -3,6 +3,9 @@ package ca.uhn.fhir.jpa.dao.data;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
@ -36,7 +39,7 @@ public interface ISearchDao extends JpaRepository<Search, Long> {
|
||||
public Search findByUuid(@Param("uuid") String theUuid);
|
||||
|
||||
@Query("SELECT s.myId FROM Search s WHERE s.mySearchLastReturned < :cutoff")
|
||||
public Collection<Long> findWhereLastReturnedBefore(@Param("cutoff") Date theCutoff);
|
||||
public Slice<Long> findWhereLastReturnedBefore(@Param("cutoff") Date theCutoff, Pageable thePage);
|
||||
|
||||
// @Query("SELECT s FROM Search s WHERE s.myCreated < :cutoff")
|
||||
// public Collection<Search> findWhereCreatedBefore(@Param("cutoff") Date theCutoff);
|
||||
|
@ -60,7 +60,7 @@ public class FhirResourceDaoSearchParameterDstu3 extends FhirResourceDaoDstu3<Se
|
||||
ourLog.info("Marking all resources of type {} for reindexing due to updated search parameter with path: {}", expression);
|
||||
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myPlatformTransactionManager);
|
||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||
int updatedCount = txTemplate.execute(new TransactionCallback<Integer>() {
|
||||
@Override
|
||||
public Integer doInTransaction(TransactionStatus theStatus) {
|
||||
|
@ -104,6 +104,8 @@ public class FhirResourceDaoSubscriptionDstu3 extends FhirResourceDaoDstu3<Subsc
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.NOT_SUPPORTED)
|
||||
@Override
|
||||
public int pollForNewUndeliveredResources() {
|
||||
return pollForNewUndeliveredResources((String) null);
|
||||
}
|
||||
|
@ -19,13 +19,16 @@ package ca.uhn.fhir.jpa.dao.dstu3;
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.persistence.TypedQuery;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.*;
|
||||
@ -85,6 +88,8 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
|
||||
for (final BundleEntryComponent nextRequestEntry : theRequest.getEntry()) {
|
||||
|
||||
BaseServerResponseExceptionHolder caughtEx = new BaseServerResponseExceptionHolder();
|
||||
|
||||
TransactionCallback<Bundle> callback = new TransactionCallback<Bundle>() {
|
||||
@Override
|
||||
public Bundle doInTransaction(TransactionStatus theStatus) {
|
||||
@ -97,13 +102,12 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
}
|
||||
};
|
||||
|
||||
BaseServerResponseException caughtEx;
|
||||
try {
|
||||
Bundle nextResponseBundle = txTemplate.execute(callback);
|
||||
caughtEx = null;
|
||||
Bundle nextResponseBundle = callback.doInTransaction(null);
|
||||
|
||||
BundleEntryComponent subResponseEntry = nextResponseBundle.getEntry().get(0);
|
||||
resp.addEntry(subResponseEntry);
|
||||
|
||||
/*
|
||||
* If the individual entry didn't have a resource in its response, bring the sub-transaction's OperationOutcome across so the client can see it
|
||||
*/
|
||||
@ -112,21 +116,19 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
}
|
||||
|
||||
} catch (BaseServerResponseException e) {
|
||||
caughtEx = e;
|
||||
caughtEx.setException(e);
|
||||
} catch (Throwable t) {
|
||||
ourLog.error("Failure during BATCH sub transaction processing", t);
|
||||
caughtEx = new InternalErrorException(t);
|
||||
caughtEx.setException(new InternalErrorException(t));
|
||||
}
|
||||
|
||||
if (caughtEx != null) {
|
||||
if (caughtEx.getException() != null) {
|
||||
BundleEntryComponent nextEntry = resp.addEntry();
|
||||
|
||||
OperationOutcome oo = new OperationOutcome();
|
||||
oo.addIssue().setSeverity(IssueSeverity.ERROR).setDiagnostics(caughtEx.getMessage());
|
||||
nextEntry.setResource(oo);
|
||||
populateEntryWithOperationOutcome(caughtEx.getException(), nextEntry);
|
||||
|
||||
BundleEntryResponseComponent nextEntryResp = nextEntry.getResponse();
|
||||
nextEntryResp.setStatus(toStatusString(caughtEx.getStatusCode()));
|
||||
nextEntryResp.setStatus(toStatusString(caughtEx.getException().getStatusCode()));
|
||||
}
|
||||
|
||||
}
|
||||
@ -137,8 +139,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
return resp;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Bundle doTransaction(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName) {
|
||||
private Bundle doTransaction(final ServletRequestDetails theRequestDetails, final Bundle theRequest, final String theActionName) {
|
||||
BundleType transactionType = theRequest.getTypeElement().getValue();
|
||||
if (transactionType == BundleType.BATCH) {
|
||||
return batch(theRequestDetails, theRequest);
|
||||
@ -156,11 +157,11 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
ourLog.info("Beginning {} with {} resources", theActionName, theRequest.getEntry().size());
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
Date updateTime = new Date();
|
||||
final Date updateTime = new Date();
|
||||
|
||||
Set<IdType> allIds = new LinkedHashSet<IdType>();
|
||||
Map<IdType, IdType> idSubstitutions = new HashMap<IdType, IdType>();
|
||||
Map<IdType, DaoMethodOutcome> idToPersistedOutcome = new HashMap<IdType, DaoMethodOutcome>();
|
||||
final Set<IdType> allIds = new LinkedHashSet<IdType>();
|
||||
final Map<IdType, IdType> idSubstitutions = new HashMap<IdType, IdType>();
|
||||
final Map<IdType, DaoMethodOutcome> idToPersistedOutcome = new HashMap<IdType, DaoMethodOutcome>();
|
||||
|
||||
// Do all entries have a verb?
|
||||
for (int i = 0; i < theRequest.getEntry().size(); i++) {
|
||||
@ -181,9 +182,9 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
* are saved in a two-phase way in order to deal with interdependencies, and
|
||||
* we want the GET processing to use the final indexing state
|
||||
*/
|
||||
Bundle response = new Bundle();
|
||||
final Bundle response = new Bundle();
|
||||
List<BundleEntryComponent> getEntries = new ArrayList<BundleEntryComponent>();
|
||||
IdentityHashMap<BundleEntryComponent, Integer> originalRequestOrder = new IdentityHashMap<Bundle.BundleEntryComponent, Integer>();
|
||||
final IdentityHashMap<BundleEntryComponent, Integer> originalRequestOrder = new IdentityHashMap<Bundle.BundleEntryComponent, Integer>();
|
||||
for (int i = 0; i < theRequest.getEntry().size(); i++) {
|
||||
originalRequestOrder.put(theRequest.getEntry().get(i), i);
|
||||
response.addEntry();
|
||||
@ -192,20 +193,13 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> deletedResources = new HashSet<String>();
|
||||
List<DeleteConflict> deleteConflicts = new ArrayList<DeleteConflict>();
|
||||
Map<BundleEntryComponent, ResourceTable> entriesToProcess = new IdentityHashMap<BundleEntryComponent, ResourceTable>();
|
||||
Set<ResourceTable> nonUpdatedEntities = new HashSet<ResourceTable>();
|
||||
Map<String, Class<? extends IBaseResource>> conditionalRequestUrls = new HashMap<String, Class<? extends IBaseResource>>();
|
||||
|
||||
List<BundleEntryComponent> entries = new ArrayList<BundleEntryComponent>(theRequest.getEntry());
|
||||
|
||||
/*
|
||||
* See FhirSystemDaoDstu3Test#testTransactionWithPlaceholderIdInMatchUrl
|
||||
* Basically if the resource has a match URL that references a placeholder,
|
||||
* we try to handle the resource with the placeholder first.
|
||||
*/
|
||||
Set<String> placeholderIds = new HashSet<String>();
|
||||
final List<BundleEntryComponent> entries = theRequest.getEntry();
|
||||
for (BundleEntryComponent nextEntry : entries) {
|
||||
if (isNotBlank(nextEntry.getFullUrl()) && nextEntry.getFullUrl().startsWith(IdType.URN_PREFIX)) {
|
||||
placeholderIds.add(nextEntry.getFullUrl());
|
||||
@ -213,17 +207,124 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
}
|
||||
Collections.sort(entries, new TransactionSorter(placeholderIds));
|
||||
|
||||
/*
|
||||
* All of the write operations in the transaction (PUT, POST, etc.. basically anything
|
||||
* except GET) are performed in their own database transaction before we do the reads.
|
||||
* We do this because the reads (specifically the searches) often spawn their own
|
||||
* secondary database transaction and if we allow that within the primary
|
||||
* database transaction we can end up with deadlocks if the server is under
|
||||
* heavy load with lots of concurrent transactions using all available
|
||||
* database connections.
|
||||
*/
|
||||
TransactionTemplate txManager = new TransactionTemplate(myTxManager);
|
||||
Map<BundleEntryComponent, ResourceTable> entriesToProcess = txManager.execute(new TransactionCallback<Map<BundleEntryComponent, ResourceTable>>() {
|
||||
@Override
|
||||
public Map<BundleEntryComponent, ResourceTable> doInTransaction(TransactionStatus status) {
|
||||
return doTransactionWriteOperations(theRequestDetails, theRequest, theActionName, updateTime, allIds, idSubstitutions, idToPersistedOutcome, response, originalRequestOrder, entries);
|
||||
}
|
||||
});
|
||||
for (Entry<BundleEntryComponent, ResourceTable> nextEntry : entriesToProcess.entrySet()) {
|
||||
String responseLocation = nextEntry.getValue().getIdDt().toUnqualified().getValue();
|
||||
String responseEtag = nextEntry.getValue().getIdDt().getVersionIdPart();
|
||||
nextEntry.getKey().getResponse().setLocation(responseLocation);
|
||||
nextEntry.getKey().getResponse().setEtag(responseEtag);
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop through the request and process any entries of type GET
|
||||
*/
|
||||
for (int i = 0; i < getEntries.size(); i++) {
|
||||
BundleEntryComponent nextReqEntry = getEntries.get(i);
|
||||
Integer originalOrder = originalRequestOrder.get(nextReqEntry);
|
||||
BundleEntryComponent nextRespEntry = response.getEntry().get(originalOrder);
|
||||
|
||||
ServletSubRequestDetails requestDetails = new ServletSubRequestDetails();
|
||||
requestDetails.setServletRequest(theRequestDetails.getServletRequest());
|
||||
requestDetails.setRequestType(RequestTypeEnum.GET);
|
||||
requestDetails.setServer(theRequestDetails.getServer());
|
||||
|
||||
String url = extractTransactionUrlOrThrowException(nextReqEntry, HTTPVerb.GET);
|
||||
|
||||
int qIndex = url.indexOf('?');
|
||||
ArrayListMultimap<String, String> paramValues = ArrayListMultimap.create();
|
||||
requestDetails.setParameters(new HashMap<String, String[]>());
|
||||
if (qIndex != -1) {
|
||||
String params = url.substring(qIndex);
|
||||
List<NameValuePair> parameters = translateMatchUrl(params);
|
||||
for (NameValuePair next : parameters) {
|
||||
paramValues.put(next.getName(), next.getValue());
|
||||
}
|
||||
for (java.util.Map.Entry<String, Collection<String>> nextParamEntry : paramValues.asMap().entrySet()) {
|
||||
String[] nextValue = nextParamEntry.getValue().toArray(new String[nextParamEntry.getValue().size()]);
|
||||
requestDetails.getParameters().put(nextParamEntry.getKey(), nextValue);
|
||||
}
|
||||
url = url.substring(0, qIndex);
|
||||
}
|
||||
|
||||
requestDetails.setRequestPath(url);
|
||||
requestDetails.setFhirServerBase(theRequestDetails.getFhirServerBase());
|
||||
|
||||
theRequestDetails.getServer().populateRequestDetailsFromRequestPath(requestDetails, url);
|
||||
BaseMethodBinding<?> method = theRequestDetails.getServer().determineResourceMethod(requestDetails, url);
|
||||
if (method == null) {
|
||||
throw new IllegalArgumentException("Unable to handle GET " + url);
|
||||
}
|
||||
|
||||
if (isNotBlank(nextReqEntry.getRequest().getIfMatch())) {
|
||||
requestDetails.addHeader(Constants.HEADER_IF_MATCH, nextReqEntry.getRequest().getIfMatch());
|
||||
}
|
||||
if (isNotBlank(nextReqEntry.getRequest().getIfNoneExist())) {
|
||||
requestDetails.addHeader(Constants.HEADER_IF_NONE_EXIST, nextReqEntry.getRequest().getIfNoneExist());
|
||||
}
|
||||
if (isNotBlank(nextReqEntry.getRequest().getIfNoneMatch())) {
|
||||
requestDetails.addHeader(Constants.HEADER_IF_NONE_MATCH, nextReqEntry.getRequest().getIfNoneMatch());
|
||||
}
|
||||
|
||||
Validate.isTrue(method instanceof BaseResourceReturningMethodBinding, "Unable to handle GET {}", url);
|
||||
try {
|
||||
IBaseResource resource = ((BaseResourceReturningMethodBinding) method).doInvokeServer(theRequestDetails.getServer(), requestDetails);
|
||||
if (paramValues.containsKey(Constants.PARAM_SUMMARY) || paramValues.containsKey(Constants.PARAM_CONTENT)) {
|
||||
resource = filterNestedBundle(requestDetails, resource);
|
||||
}
|
||||
nextRespEntry.setResource((Resource) resource);
|
||||
nextRespEntry.getResponse().setStatus(toStatusString(Constants.STATUS_HTTP_200_OK));
|
||||
} catch (NotModifiedException e) {
|
||||
nextRespEntry.getResponse().setStatus(toStatusString(Constants.STATUS_HTTP_304_NOT_MODIFIED));
|
||||
} catch (BaseServerResponseException e) {
|
||||
ourLog.info("Failure processing transaction GET {}: {}", url, e.toString());
|
||||
nextRespEntry.getResponse().setStatus(toStatusString(e.getStatusCode()));
|
||||
populateEntryWithOperationOutcome(e, nextRespEntry);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
long delay = System.currentTimeMillis() - start;
|
||||
ourLog.info(theActionName + " completed in {}ms", new Object[] { delay });
|
||||
|
||||
response.setType(BundleType.TRANSACTIONRESPONSE);
|
||||
return response;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<BundleEntryComponent, ResourceTable> doTransactionWriteOperations(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName, Date updateTime, Set<IdType> allIds,
|
||||
Map<IdType, IdType> idSubstitutions, Map<IdType, DaoMethodOutcome> idToPersistedOutcome, Bundle response, IdentityHashMap<BundleEntryComponent, Integer> originalRequestOrder, List<BundleEntryComponent> theEntries) {
|
||||
Set<String> deletedResources = new HashSet<String>();
|
||||
List<DeleteConflict> deleteConflicts = new ArrayList<DeleteConflict>();
|
||||
Map<BundleEntryComponent, ResourceTable> entriesToProcess = new IdentityHashMap<BundleEntryComponent, ResourceTable>();
|
||||
Set<ResourceTable> nonUpdatedEntities = new HashSet<ResourceTable>();
|
||||
Map<String, Class<? extends IBaseResource>> conditionalRequestUrls = new HashMap<String, Class<? extends IBaseResource>>();
|
||||
|
||||
/*
|
||||
* Loop through the request and process any entries of type
|
||||
* PUT, POST or DELETE
|
||||
*/
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
for (int i = 0; i < theEntries.size(); i++) {
|
||||
|
||||
if (i % 100 == 0) {
|
||||
ourLog.info("Processed {} non-GET entries out of {}", i, entries.size());
|
||||
ourLog.info("Processed {} non-GET entries out of {}", i, theEntries.size());
|
||||
}
|
||||
|
||||
BundleEntryComponent nextReqEntry = entries.get(i);
|
||||
BundleEntryComponent nextReqEntry = theEntries.get(i);
|
||||
Resource res = nextReqEntry.getResource();
|
||||
IdType nextResourceId = null;
|
||||
if (res != null) {
|
||||
@ -435,86 +536,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
}
|
||||
ourLog.info("Placeholder resource ID \"{}\" was replaced with permanent ID \"{}\"", next, replacement);
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop through the request and process any entries of type GET
|
||||
*/
|
||||
for (int i = 0; i < getEntries.size(); i++) {
|
||||
BundleEntryComponent nextReqEntry = getEntries.get(i);
|
||||
Integer originalOrder = originalRequestOrder.get(nextReqEntry);
|
||||
BundleEntryComponent nextRespEntry = response.getEntry().get(originalOrder);
|
||||
|
||||
ServletSubRequestDetails requestDetails = new ServletSubRequestDetails();
|
||||
requestDetails.setServletRequest(theRequestDetails.getServletRequest());
|
||||
requestDetails.setRequestType(RequestTypeEnum.GET);
|
||||
requestDetails.setServer(theRequestDetails.getServer());
|
||||
|
||||
String url = extractTransactionUrlOrThrowException(nextReqEntry, HTTPVerb.GET);
|
||||
|
||||
int qIndex = url.indexOf('?');
|
||||
ArrayListMultimap<String, String> paramValues = ArrayListMultimap.create();
|
||||
requestDetails.setParameters(new HashMap<String, String[]>());
|
||||
if (qIndex != -1) {
|
||||
String params = url.substring(qIndex);
|
||||
List<NameValuePair> parameters = translateMatchUrl(params);
|
||||
for (NameValuePair next : parameters) {
|
||||
paramValues.put(next.getName(), next.getValue());
|
||||
}
|
||||
for (java.util.Map.Entry<String, Collection<String>> nextParamEntry : paramValues.asMap().entrySet()) {
|
||||
String[] nextValue = nextParamEntry.getValue().toArray(new String[nextParamEntry.getValue().size()]);
|
||||
requestDetails.getParameters().put(nextParamEntry.getKey(), nextValue);
|
||||
}
|
||||
url = url.substring(0, qIndex);
|
||||
}
|
||||
|
||||
requestDetails.setRequestPath(url);
|
||||
requestDetails.setFhirServerBase(theRequestDetails.getFhirServerBase());
|
||||
|
||||
theRequestDetails.getServer().populateRequestDetailsFromRequestPath(requestDetails, url);
|
||||
BaseMethodBinding<?> method = theRequestDetails.getServer().determineResourceMethod(requestDetails, url);
|
||||
if (method == null) {
|
||||
throw new IllegalArgumentException("Unable to handle GET " + url);
|
||||
}
|
||||
|
||||
if (isNotBlank(nextReqEntry.getRequest().getIfMatch())) {
|
||||
requestDetails.addHeader(Constants.HEADER_IF_MATCH, nextReqEntry.getRequest().getIfMatch());
|
||||
}
|
||||
if (isNotBlank(nextReqEntry.getRequest().getIfNoneExist())) {
|
||||
requestDetails.addHeader(Constants.HEADER_IF_NONE_EXIST, nextReqEntry.getRequest().getIfNoneExist());
|
||||
}
|
||||
if (isNotBlank(nextReqEntry.getRequest().getIfNoneMatch())) {
|
||||
requestDetails.addHeader(Constants.HEADER_IF_NONE_MATCH, nextReqEntry.getRequest().getIfNoneMatch());
|
||||
}
|
||||
|
||||
if (method instanceof BaseResourceReturningMethodBinding) {
|
||||
try {
|
||||
IBaseResource resource = ((BaseResourceReturningMethodBinding) method).doInvokeServer(theRequestDetails.getServer(), requestDetails);
|
||||
if (paramValues.containsKey(Constants.PARAM_SUMMARY) || paramValues.containsKey(Constants.PARAM_CONTENT)) {
|
||||
resource = filterNestedBundle(requestDetails, resource);
|
||||
}
|
||||
nextRespEntry.setResource((Resource) resource);
|
||||
nextRespEntry.getResponse().setStatus(toStatusString(Constants.STATUS_HTTP_200_OK));
|
||||
} catch (NotModifiedException e) {
|
||||
nextRespEntry.getResponse().setStatus(toStatusString(Constants.STATUS_HTTP_304_NOT_MODIFIED));
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unable to handle GET " + url);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (Entry<BundleEntryComponent, ResourceTable> nextEntry : entriesToProcess.entrySet()) {
|
||||
String responseLocation = nextEntry.getValue().getIdDt().toUnqualified().getValue();
|
||||
String responseEtag = nextEntry.getValue().getIdDt().getVersionIdPart();
|
||||
nextEntry.getKey().getResponse().setLocation(responseLocation);
|
||||
nextEntry.getKey().getResponse().setEtag(responseEtag);
|
||||
}
|
||||
|
||||
long delay = System.currentTimeMillis() - start;
|
||||
ourLog.info(theActionName + " completed in {}ms", new Object[] { delay });
|
||||
|
||||
response.setType(BundleType.TRANSACTIONRESPONSE);
|
||||
return response;
|
||||
return entriesToProcess;
|
||||
}
|
||||
|
||||
private String extractTransactionUrlOrThrowException(BundleEntryComponent nextEntry, HTTPVerb verb) {
|
||||
@ -562,20 +584,10 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private String performIdSubstitutionsInMatchUrl(Map<IdType, IdType> theIdSubstitutions, String theMatchUrl) {
|
||||
String matchUrl = theMatchUrl;
|
||||
if (isNotBlank(matchUrl)) {
|
||||
for (Entry<IdType, IdType> nextSubstitutionEntry : theIdSubstitutions.entrySet()) {
|
||||
IdType nextTemporaryId = nextSubstitutionEntry.getKey();
|
||||
IdType nextReplacementId = nextSubstitutionEntry.getValue();
|
||||
String nextTemporaryIdPart = nextTemporaryId.getIdPart();
|
||||
String nextReplacementIdPart = nextReplacementId.getValueAsString();
|
||||
if (nextTemporaryId.isUrn() && nextTemporaryIdPart.length() > IdType.URN_PREFIX.length()) {
|
||||
matchUrl = matchUrl.replace(nextTemporaryIdPart, nextReplacementIdPart);
|
||||
}
|
||||
}
|
||||
}
|
||||
return matchUrl;
|
||||
private void populateEntryWithOperationOutcome(BaseServerResponseException caughtEx, BundleEntryComponent nextEntry) {
|
||||
OperationOutcome oo = new OperationOutcome();
|
||||
oo.addIssue().setSeverity(IssueSeverity.ERROR).setDiagnostics(caughtEx.getMessage());
|
||||
nextEntry.getResponse().setOutcome(oo);
|
||||
}
|
||||
|
||||
private ca.uhn.fhir.jpa.dao.IFhirResourceDao<? extends IBaseResource> toDao(UrlParts theParts, String theVerb, String theUrl) {
|
||||
@ -621,7 +633,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
@Transactional(propagation = Propagation.NEVER)
|
||||
@Override
|
||||
public Bundle transaction(RequestDetails theRequestDetails, Bundle theRequest) {
|
||||
if (theRequestDetails != null) {
|
||||
@ -633,6 +645,26 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
return transaction((ServletRequestDetails) theRequestDetails, theRequest, actionName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private String performIdSubstitutionsInMatchUrl(Map<IdType, IdType> theIdSubstitutions, String theMatchUrl) {
|
||||
String matchUrl = theMatchUrl;
|
||||
if (isNotBlank(matchUrl)) {
|
||||
for (Entry<IdType, IdType> nextSubstitutionEntry : theIdSubstitutions.entrySet()) {
|
||||
IdType nextTemporaryId = nextSubstitutionEntry.getKey();
|
||||
IdType nextReplacementId = nextSubstitutionEntry.getValue();
|
||||
String nextTemporaryIdPart = nextTemporaryId.getIdPart();
|
||||
String nextReplacementIdPart = nextReplacementId.getValueAsString();
|
||||
if (nextTemporaryId.isUrn() && nextTemporaryIdPart.length() > IdType.URN_PREFIX.length()) {
|
||||
matchUrl = matchUrl.replace(nextTemporaryIdPart, nextReplacementIdPart);
|
||||
}
|
||||
}
|
||||
}
|
||||
return matchUrl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private Bundle transaction(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName) {
|
||||
super.markRequestAsProcessingSubRequest(theRequestDetails);
|
||||
try {
|
||||
@ -690,6 +722,20 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
return Integer.toString(theStatusCode) + " " + defaultString(Constants.HTTP_STATUS_NAMES.get(theStatusCode));
|
||||
}
|
||||
|
||||
private static class BaseServerResponseExceptionHolder
|
||||
{
|
||||
private BaseServerResponseException myException;
|
||||
|
||||
public BaseServerResponseException getException() {
|
||||
return myException;
|
||||
}
|
||||
|
||||
public void setException(BaseServerResponseException myException) {
|
||||
this.myException = myException;
|
||||
}
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
/**
|
||||
* Transaction Order, per the spec:
|
||||
*
|
||||
@ -698,6 +744,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
* Process any PUT interactions
|
||||
* Process any GET interactions
|
||||
*/
|
||||
//@formatter:off
|
||||
public class TransactionSorter implements Comparator<BundleEntryComponent> {
|
||||
|
||||
private Set<String> myPlaceholderIds;
|
||||
|
@ -24,8 +24,8 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.hl7.fhir.r4.hapi.validation.IValidationSupport.CodeValidationResult;
|
||||
import org.hl7.fhir.r4.hapi.validation.ValidationSupportChain;
|
||||
import org.hl7.fhir.r4.hapi.ctx.ValidationSupportChain;
|
||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport.CodeValidationResult;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode;
|
||||
import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
|
||||
|
@ -27,8 +27,8 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.codec.binary.StringUtils;
|
||||
import org.hl7.fhir.r4.hapi.validation.HapiWorkerContext;
|
||||
import org.hl7.fhir.r4.hapi.validation.IValidationSupport;
|
||||
import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext;
|
||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Enumerations.PublicationStatus;
|
||||
import org.hl7.fhir.r4.model.ValueSet.*;
|
||||
|
@ -19,13 +19,16 @@ package ca.uhn.fhir.jpa.dao.r4;
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.persistence.TypedQuery;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Bundle.*;
|
||||
@ -85,6 +88,8 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
|
||||
for (final BundleEntryComponent nextRequestEntry : theRequest.getEntry()) {
|
||||
|
||||
BaseServerResponseExceptionHolder caughtEx = new BaseServerResponseExceptionHolder();
|
||||
|
||||
TransactionCallback<Bundle> callback = new TransactionCallback<Bundle>() {
|
||||
@Override
|
||||
public Bundle doInTransaction(TransactionStatus theStatus) {
|
||||
@ -97,13 +102,12 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
}
|
||||
};
|
||||
|
||||
BaseServerResponseException caughtEx;
|
||||
try {
|
||||
Bundle nextResponseBundle = txTemplate.execute(callback);
|
||||
caughtEx = null;
|
||||
Bundle nextResponseBundle = callback.doInTransaction(null);
|
||||
|
||||
BundleEntryComponent subResponseEntry = nextResponseBundle.getEntry().get(0);
|
||||
resp.addEntry(subResponseEntry);
|
||||
|
||||
/*
|
||||
* If the individual entry didn't have a resource in its response, bring the sub-transaction's OperationOutcome across so the client can see it
|
||||
*/
|
||||
@ -112,21 +116,19 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
}
|
||||
|
||||
} catch (BaseServerResponseException e) {
|
||||
caughtEx = e;
|
||||
caughtEx.setException(e);
|
||||
} catch (Throwable t) {
|
||||
ourLog.error("Failure during BATCH sub transaction processing", t);
|
||||
caughtEx = new InternalErrorException(t);
|
||||
caughtEx.setException(new InternalErrorException(t));
|
||||
}
|
||||
|
||||
if (caughtEx != null) {
|
||||
if (caughtEx.getException() != null) {
|
||||
BundleEntryComponent nextEntry = resp.addEntry();
|
||||
|
||||
OperationOutcome oo = new OperationOutcome();
|
||||
oo.addIssue().setSeverity(IssueSeverity.ERROR).setDiagnostics(caughtEx.getMessage());
|
||||
nextEntry.setResource(oo);
|
||||
populateEntryWithOperationOutcome(caughtEx.getException(), nextEntry);
|
||||
|
||||
BundleEntryResponseComponent nextEntryResp = nextEntry.getResponse();
|
||||
nextEntryResp.setStatus(toStatusString(caughtEx.getStatusCode()));
|
||||
nextEntryResp.setStatus(toStatusString(caughtEx.getException().getStatusCode()));
|
||||
}
|
||||
|
||||
}
|
||||
@ -137,8 +139,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
return resp;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Bundle doTransaction(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName) {
|
||||
private Bundle doTransaction(final ServletRequestDetails theRequestDetails, final Bundle theRequest, final String theActionName) {
|
||||
BundleType transactionType = theRequest.getTypeElement().getValue();
|
||||
if (transactionType == BundleType.BATCH) {
|
||||
return batch(theRequestDetails, theRequest);
|
||||
@ -156,11 +157,11 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
ourLog.info("Beginning {} with {} resources", theActionName, theRequest.getEntry().size());
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
Date updateTime = new Date();
|
||||
final Date updateTime = new Date();
|
||||
|
||||
Set<IdType> allIds = new LinkedHashSet<IdType>();
|
||||
Map<IdType, IdType> idSubstitutions = new HashMap<IdType, IdType>();
|
||||
Map<IdType, DaoMethodOutcome> idToPersistedOutcome = new HashMap<IdType, DaoMethodOutcome>();
|
||||
final Set<IdType> allIds = new LinkedHashSet<IdType>();
|
||||
final Map<IdType, IdType> idSubstitutions = new HashMap<IdType, IdType>();
|
||||
final Map<IdType, DaoMethodOutcome> idToPersistedOutcome = new HashMap<IdType, DaoMethodOutcome>();
|
||||
|
||||
// Do all entries have a verb?
|
||||
for (int i = 0; i < theRequest.getEntry().size(); i++) {
|
||||
@ -181,9 +182,9 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
* are saved in a two-phase way in order to deal with interdependencies, and
|
||||
* we want the GET processing to use the final indexing state
|
||||
*/
|
||||
Bundle response = new Bundle();
|
||||
final Bundle response = new Bundle();
|
||||
List<BundleEntryComponent> getEntries = new ArrayList<BundleEntryComponent>();
|
||||
IdentityHashMap<BundleEntryComponent, Integer> originalRequestOrder = new IdentityHashMap<Bundle.BundleEntryComponent, Integer>();
|
||||
final IdentityHashMap<BundleEntryComponent, Integer> originalRequestOrder = new IdentityHashMap<Bundle.BundleEntryComponent, Integer>();
|
||||
for (int i = 0; i < theRequest.getEntry().size(); i++) {
|
||||
originalRequestOrder.put(theRequest.getEntry().get(i), i);
|
||||
response.addEntry();
|
||||
@ -192,20 +193,13 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> deletedResources = new HashSet<String>();
|
||||
List<DeleteConflict> deleteConflicts = new ArrayList<DeleteConflict>();
|
||||
Map<BundleEntryComponent, ResourceTable> entriesToProcess = new IdentityHashMap<BundleEntryComponent, ResourceTable>();
|
||||
Set<ResourceTable> nonUpdatedEntities = new HashSet<ResourceTable>();
|
||||
Map<String, Class<? extends IBaseResource>> conditionalRequestUrls = new HashMap<String, Class<? extends IBaseResource>>();
|
||||
|
||||
List<BundleEntryComponent> entries = new ArrayList<BundleEntryComponent>(theRequest.getEntry());
|
||||
|
||||
/*
|
||||
* See FhirSystemDaoDstu3Test#testTransactionWithPlaceholderIdInMatchUrl
|
||||
* Basically if the resource has a match URL that references a placeholder,
|
||||
* we try to handle the resource with the placeholder first.
|
||||
*/
|
||||
Set<String> placeholderIds = new HashSet<String>();
|
||||
final List<BundleEntryComponent> entries = theRequest.getEntry();
|
||||
for (BundleEntryComponent nextEntry : entries) {
|
||||
if (isNotBlank(nextEntry.getFullUrl()) && nextEntry.getFullUrl().startsWith(IdType.URN_PREFIX)) {
|
||||
placeholderIds.add(nextEntry.getFullUrl());
|
||||
@ -213,17 +207,124 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
}
|
||||
Collections.sort(entries, new TransactionSorter(placeholderIds));
|
||||
|
||||
/*
|
||||
* All of the write operations in the transaction (PUT, POST, etc.. basically anything
|
||||
* except GET) are performed in their own database transaction before we do the reads.
|
||||
* We do this because the reads (specifically the searches) often spawn their own
|
||||
* secondary database transaction and if we allow that within the primary
|
||||
* database transaction we can end up with deadlocks if the server is under
|
||||
* heavy load with lots of concurrent transactions using all available
|
||||
* database connections.
|
||||
*/
|
||||
TransactionTemplate txManager = new TransactionTemplate(myTxManager);
|
||||
Map<BundleEntryComponent, ResourceTable> entriesToProcess = txManager.execute(new TransactionCallback<Map<BundleEntryComponent, ResourceTable>>() {
|
||||
@Override
|
||||
public Map<BundleEntryComponent, ResourceTable> doInTransaction(TransactionStatus status) {
|
||||
return doTransactionWriteOperations(theRequestDetails, theRequest, theActionName, updateTime, allIds, idSubstitutions, idToPersistedOutcome, response, originalRequestOrder, entries);
|
||||
}
|
||||
});
|
||||
for (Entry<BundleEntryComponent, ResourceTable> nextEntry : entriesToProcess.entrySet()) {
|
||||
String responseLocation = nextEntry.getValue().getIdDt().toUnqualified().getValue();
|
||||
String responseEtag = nextEntry.getValue().getIdDt().getVersionIdPart();
|
||||
nextEntry.getKey().getResponse().setLocation(responseLocation);
|
||||
nextEntry.getKey().getResponse().setEtag(responseEtag);
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop through the request and process any entries of type GET
|
||||
*/
|
||||
for (int i = 0; i < getEntries.size(); i++) {
|
||||
BundleEntryComponent nextReqEntry = getEntries.get(i);
|
||||
Integer originalOrder = originalRequestOrder.get(nextReqEntry);
|
||||
BundleEntryComponent nextRespEntry = response.getEntry().get(originalOrder);
|
||||
|
||||
ServletSubRequestDetails requestDetails = new ServletSubRequestDetails();
|
||||
requestDetails.setServletRequest(theRequestDetails.getServletRequest());
|
||||
requestDetails.setRequestType(RequestTypeEnum.GET);
|
||||
requestDetails.setServer(theRequestDetails.getServer());
|
||||
|
||||
String url = extractTransactionUrlOrThrowException(nextReqEntry, HTTPVerb.GET);
|
||||
|
||||
int qIndex = url.indexOf('?');
|
||||
ArrayListMultimap<String, String> paramValues = ArrayListMultimap.create();
|
||||
requestDetails.setParameters(new HashMap<String, String[]>());
|
||||
if (qIndex != -1) {
|
||||
String params = url.substring(qIndex);
|
||||
List<NameValuePair> parameters = translateMatchUrl(params);
|
||||
for (NameValuePair next : parameters) {
|
||||
paramValues.put(next.getName(), next.getValue());
|
||||
}
|
||||
for (java.util.Map.Entry<String, Collection<String>> nextParamEntry : paramValues.asMap().entrySet()) {
|
||||
String[] nextValue = nextParamEntry.getValue().toArray(new String[nextParamEntry.getValue().size()]);
|
||||
requestDetails.getParameters().put(nextParamEntry.getKey(), nextValue);
|
||||
}
|
||||
url = url.substring(0, qIndex);
|
||||
}
|
||||
|
||||
requestDetails.setRequestPath(url);
|
||||
requestDetails.setFhirServerBase(theRequestDetails.getFhirServerBase());
|
||||
|
||||
theRequestDetails.getServer().populateRequestDetailsFromRequestPath(requestDetails, url);
|
||||
BaseMethodBinding<?> method = theRequestDetails.getServer().determineResourceMethod(requestDetails, url);
|
||||
if (method == null) {
|
||||
throw new IllegalArgumentException("Unable to handle GET " + url);
|
||||
}
|
||||
|
||||
if (isNotBlank(nextReqEntry.getRequest().getIfMatch())) {
|
||||
requestDetails.addHeader(Constants.HEADER_IF_MATCH, nextReqEntry.getRequest().getIfMatch());
|
||||
}
|
||||
if (isNotBlank(nextReqEntry.getRequest().getIfNoneExist())) {
|
||||
requestDetails.addHeader(Constants.HEADER_IF_NONE_EXIST, nextReqEntry.getRequest().getIfNoneExist());
|
||||
}
|
||||
if (isNotBlank(nextReqEntry.getRequest().getIfNoneMatch())) {
|
||||
requestDetails.addHeader(Constants.HEADER_IF_NONE_MATCH, nextReqEntry.getRequest().getIfNoneMatch());
|
||||
}
|
||||
|
||||
Validate.isTrue(method instanceof BaseResourceReturningMethodBinding, "Unable to handle GET {}", url);
|
||||
try {
|
||||
IBaseResource resource = ((BaseResourceReturningMethodBinding) method).doInvokeServer(theRequestDetails.getServer(), requestDetails);
|
||||
if (paramValues.containsKey(Constants.PARAM_SUMMARY) || paramValues.containsKey(Constants.PARAM_CONTENT)) {
|
||||
resource = filterNestedBundle(requestDetails, resource);
|
||||
}
|
||||
nextRespEntry.setResource((Resource) resource);
|
||||
nextRespEntry.getResponse().setStatus(toStatusString(Constants.STATUS_HTTP_200_OK));
|
||||
} catch (NotModifiedException e) {
|
||||
nextRespEntry.getResponse().setStatus(toStatusString(Constants.STATUS_HTTP_304_NOT_MODIFIED));
|
||||
} catch (BaseServerResponseException e) {
|
||||
ourLog.info("Failure processing transaction GET {}: {}", url, e.toString());
|
||||
nextRespEntry.getResponse().setStatus(toStatusString(e.getStatusCode()));
|
||||
populateEntryWithOperationOutcome(e, nextRespEntry);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
long delay = System.currentTimeMillis() - start;
|
||||
ourLog.info(theActionName + " completed in {}ms", new Object[] { delay });
|
||||
|
||||
response.setType(BundleType.TRANSACTIONRESPONSE);
|
||||
return response;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<BundleEntryComponent, ResourceTable> doTransactionWriteOperations(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName, Date updateTime, Set<IdType> allIds,
|
||||
Map<IdType, IdType> idSubstitutions, Map<IdType, DaoMethodOutcome> idToPersistedOutcome, Bundle response, IdentityHashMap<BundleEntryComponent, Integer> originalRequestOrder, List<BundleEntryComponent> theEntries) {
|
||||
Set<String> deletedResources = new HashSet<String>();
|
||||
List<DeleteConflict> deleteConflicts = new ArrayList<DeleteConflict>();
|
||||
Map<BundleEntryComponent, ResourceTable> entriesToProcess = new IdentityHashMap<BundleEntryComponent, ResourceTable>();
|
||||
Set<ResourceTable> nonUpdatedEntities = new HashSet<ResourceTable>();
|
||||
Map<String, Class<? extends IBaseResource>> conditionalRequestUrls = new HashMap<String, Class<? extends IBaseResource>>();
|
||||
|
||||
/*
|
||||
* Loop through the request and process any entries of type
|
||||
* PUT, POST or DELETE
|
||||
*/
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
for (int i = 0; i < theEntries.size(); i++) {
|
||||
|
||||
if (i % 100 == 0) {
|
||||
ourLog.info("Processed {} non-GET entries out of {}", i, entries.size());
|
||||
ourLog.info("Processed {} non-GET entries out of {}", i, theEntries.size());
|
||||
}
|
||||
|
||||
BundleEntryComponent nextReqEntry = entries.get(i);
|
||||
BundleEntryComponent nextReqEntry = theEntries.get(i);
|
||||
Resource res = nextReqEntry.getResource();
|
||||
IdType nextResourceId = null;
|
||||
if (res != null) {
|
||||
@ -435,86 +536,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
}
|
||||
ourLog.info("Placeholder resource ID \"{}\" was replaced with permanent ID \"{}\"", next, replacement);
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop through the request and process any entries of type GET
|
||||
*/
|
||||
for (int i = 0; i < getEntries.size(); i++) {
|
||||
BundleEntryComponent nextReqEntry = getEntries.get(i);
|
||||
Integer originalOrder = originalRequestOrder.get(nextReqEntry);
|
||||
BundleEntryComponent nextRespEntry = response.getEntry().get(originalOrder);
|
||||
|
||||
ServletSubRequestDetails requestDetails = new ServletSubRequestDetails();
|
||||
requestDetails.setServletRequest(theRequestDetails.getServletRequest());
|
||||
requestDetails.setRequestType(RequestTypeEnum.GET);
|
||||
requestDetails.setServer(theRequestDetails.getServer());
|
||||
|
||||
String url = extractTransactionUrlOrThrowException(nextReqEntry, HTTPVerb.GET);
|
||||
|
||||
int qIndex = url.indexOf('?');
|
||||
ArrayListMultimap<String, String> paramValues = ArrayListMultimap.create();
|
||||
requestDetails.setParameters(new HashMap<String, String[]>());
|
||||
if (qIndex != -1) {
|
||||
String params = url.substring(qIndex);
|
||||
List<NameValuePair> parameters = translateMatchUrl(params);
|
||||
for (NameValuePair next : parameters) {
|
||||
paramValues.put(next.getName(), next.getValue());
|
||||
}
|
||||
for (java.util.Map.Entry<String, Collection<String>> nextParamEntry : paramValues.asMap().entrySet()) {
|
||||
String[] nextValue = nextParamEntry.getValue().toArray(new String[nextParamEntry.getValue().size()]);
|
||||
requestDetails.getParameters().put(nextParamEntry.getKey(), nextValue);
|
||||
}
|
||||
url = url.substring(0, qIndex);
|
||||
}
|
||||
|
||||
requestDetails.setRequestPath(url);
|
||||
requestDetails.setFhirServerBase(theRequestDetails.getFhirServerBase());
|
||||
|
||||
theRequestDetails.getServer().populateRequestDetailsFromRequestPath(requestDetails, url);
|
||||
BaseMethodBinding<?> method = theRequestDetails.getServer().determineResourceMethod(requestDetails, url);
|
||||
if (method == null) {
|
||||
throw new IllegalArgumentException("Unable to handle GET " + url);
|
||||
}
|
||||
|
||||
if (isNotBlank(nextReqEntry.getRequest().getIfMatch())) {
|
||||
requestDetails.addHeader(Constants.HEADER_IF_MATCH, nextReqEntry.getRequest().getIfMatch());
|
||||
}
|
||||
if (isNotBlank(nextReqEntry.getRequest().getIfNoneExist())) {
|
||||
requestDetails.addHeader(Constants.HEADER_IF_NONE_EXIST, nextReqEntry.getRequest().getIfNoneExist());
|
||||
}
|
||||
if (isNotBlank(nextReqEntry.getRequest().getIfNoneMatch())) {
|
||||
requestDetails.addHeader(Constants.HEADER_IF_NONE_MATCH, nextReqEntry.getRequest().getIfNoneMatch());
|
||||
}
|
||||
|
||||
if (method instanceof BaseResourceReturningMethodBinding) {
|
||||
try {
|
||||
IBaseResource resource = ((BaseResourceReturningMethodBinding) method).doInvokeServer(theRequestDetails.getServer(), requestDetails);
|
||||
if (paramValues.containsKey(Constants.PARAM_SUMMARY) || paramValues.containsKey(Constants.PARAM_CONTENT)) {
|
||||
resource = filterNestedBundle(requestDetails, resource);
|
||||
}
|
||||
nextRespEntry.setResource((Resource) resource);
|
||||
nextRespEntry.getResponse().setStatus(toStatusString(Constants.STATUS_HTTP_200_OK));
|
||||
} catch (NotModifiedException e) {
|
||||
nextRespEntry.getResponse().setStatus(toStatusString(Constants.STATUS_HTTP_304_NOT_MODIFIED));
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unable to handle GET " + url);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (Entry<BundleEntryComponent, ResourceTable> nextEntry : entriesToProcess.entrySet()) {
|
||||
String responseLocation = nextEntry.getValue().getIdDt().toUnqualified().getValue();
|
||||
String responseEtag = nextEntry.getValue().getIdDt().getVersionIdPart();
|
||||
nextEntry.getKey().getResponse().setLocation(responseLocation);
|
||||
nextEntry.getKey().getResponse().setEtag(responseEtag);
|
||||
}
|
||||
|
||||
long delay = System.currentTimeMillis() - start;
|
||||
ourLog.info(theActionName + " completed in {}ms", new Object[] { delay });
|
||||
|
||||
response.setType(BundleType.TRANSACTIONRESPONSE);
|
||||
return response;
|
||||
return entriesToProcess;
|
||||
}
|
||||
|
||||
private String extractTransactionUrlOrThrowException(BundleEntryComponent nextEntry, HTTPVerb verb) {
|
||||
@ -562,20 +584,10 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private String performIdSubstitutionsInMatchUrl(Map<IdType, IdType> theIdSubstitutions, String theMatchUrl) {
|
||||
String matchUrl = theMatchUrl;
|
||||
if (isNotBlank(matchUrl)) {
|
||||
for (Entry<IdType, IdType> nextSubstitutionEntry : theIdSubstitutions.entrySet()) {
|
||||
IdType nextTemporaryId = nextSubstitutionEntry.getKey();
|
||||
IdType nextReplacementId = nextSubstitutionEntry.getValue();
|
||||
String nextTemporaryIdPart = nextTemporaryId.getIdPart();
|
||||
String nextReplacementIdPart = nextReplacementId.getValueAsString();
|
||||
if (nextTemporaryId.isUrn() && nextTemporaryIdPart.length() > IdType.URN_PREFIX.length()) {
|
||||
matchUrl = matchUrl.replace(nextTemporaryIdPart, nextReplacementIdPart);
|
||||
}
|
||||
}
|
||||
}
|
||||
return matchUrl;
|
||||
private void populateEntryWithOperationOutcome(BaseServerResponseException caughtEx, BundleEntryComponent nextEntry) {
|
||||
OperationOutcome oo = new OperationOutcome();
|
||||
oo.addIssue().setSeverity(IssueSeverity.ERROR).setDiagnostics(caughtEx.getMessage());
|
||||
nextEntry.getResponse().setOutcome(oo);
|
||||
}
|
||||
|
||||
private ca.uhn.fhir.jpa.dao.IFhirResourceDao<? extends IBaseResource> toDao(UrlParts theParts, String theVerb, String theUrl) {
|
||||
@ -621,7 +633,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
@Transactional(propagation = Propagation.NEVER)
|
||||
@Override
|
||||
public Bundle transaction(RequestDetails theRequestDetails, Bundle theRequest) {
|
||||
if (theRequestDetails != null) {
|
||||
@ -633,6 +645,26 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
return transaction((ServletRequestDetails) theRequestDetails, theRequest, actionName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private String performIdSubstitutionsInMatchUrl(Map<IdType, IdType> theIdSubstitutions, String theMatchUrl) {
|
||||
String matchUrl = theMatchUrl;
|
||||
if (isNotBlank(matchUrl)) {
|
||||
for (Entry<IdType, IdType> nextSubstitutionEntry : theIdSubstitutions.entrySet()) {
|
||||
IdType nextTemporaryId = nextSubstitutionEntry.getKey();
|
||||
IdType nextReplacementId = nextSubstitutionEntry.getValue();
|
||||
String nextTemporaryIdPart = nextTemporaryId.getIdPart();
|
||||
String nextReplacementIdPart = nextReplacementId.getValueAsString();
|
||||
if (nextTemporaryId.isUrn() && nextTemporaryIdPart.length() > IdType.URN_PREFIX.length()) {
|
||||
matchUrl = matchUrl.replace(nextTemporaryIdPart, nextReplacementIdPart);
|
||||
}
|
||||
}
|
||||
}
|
||||
return matchUrl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private Bundle transaction(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName) {
|
||||
super.markRequestAsProcessingSubRequest(theRequestDetails);
|
||||
try {
|
||||
@ -690,6 +722,20 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
return Integer.toString(theStatusCode) + " " + defaultString(Constants.HTTP_STATUS_NAMES.get(theStatusCode));
|
||||
}
|
||||
|
||||
private static class BaseServerResponseExceptionHolder
|
||||
{
|
||||
private BaseServerResponseException myException;
|
||||
|
||||
public BaseServerResponseException getException() {
|
||||
return myException;
|
||||
}
|
||||
|
||||
public void setException(BaseServerResponseException myException) {
|
||||
this.myException = myException;
|
||||
}
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
/**
|
||||
* Transaction Order, per the spec:
|
||||
*
|
||||
@ -698,6 +744,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
* Process any PUT interactions
|
||||
* Process any GET interactions
|
||||
*/
|
||||
//@formatter:off
|
||||
public class TransactionSorter implements Comparator<BundleEntryComponent> {
|
||||
|
||||
private Set<String> myPlaceholderIds;
|
||||
|
@ -1,6 +1,6 @@
|
||||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import org.hl7.fhir.r4.hapi.validation.IValidationSupport;
|
||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
|
@ -31,7 +31,7 @@ import javax.measure.unit.Unit;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.hl7.fhir.r4.context.IWorkerContext;
|
||||
import org.hl7.fhir.r4.hapi.validation.IValidationSupport;
|
||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestSecurityComponent;
|
||||
import org.hl7.fhir.r4.model.Enumeration;
|
||||
@ -55,7 +55,7 @@ public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParamExtractorR4.class);
|
||||
|
||||
@Autowired
|
||||
private org.hl7.fhir.r4.hapi.validation.IValidationSupport myValidationSupport;
|
||||
private org.hl7.fhir.r4.hapi.ctx.IValidationSupport myValidationSupport;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@ -686,7 +686,7 @@ public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements
|
||||
*/
|
||||
@Override
|
||||
protected List<Object> extractValues(String thePaths, IBaseResource theResource) {
|
||||
IWorkerContext worker = new org.hl7.fhir.r4.hapi.validation.HapiWorkerContext(getContext(), myValidationSupport);
|
||||
IWorkerContext worker = new org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext(getContext(), myValidationSupport);
|
||||
FHIRPathEngine fp = new FHIRPathEngine(worker);
|
||||
|
||||
List<Object> values = new ArrayList<Object>();
|
||||
@ -732,7 +732,7 @@ public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setValidationSupportForTesting(org.hl7.fhir.r4.hapi.validation.IValidationSupport theValidationSupport) {
|
||||
void setValidationSupportForTesting(org.hl7.fhir.r4.hapi.ctx.IValidationSupport theValidationSupport) {
|
||||
myValidationSupport = theValidationSupport;
|
||||
}
|
||||
|
||||
|
@ -34,12 +34,10 @@ import javax.persistence.SequenceGenerator;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
//@formatter:off
|
||||
@Entity
|
||||
@Table(name = "HFJ_SEARCH_RESULT", uniqueConstraints= {
|
||||
@UniqueConstraint(name="IDX_SEARCHRES_ORDER", columnNames= {"SEARCH_PID", "SEARCH_ORDER"})
|
||||
})
|
||||
//@formatter:on
|
||||
public class SearchResult implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
@ -79,7 +79,12 @@ public class RestHookSubscriptionDstu2Interceptor extends BaseRestHookSubscripti
|
||||
* @param theOperation
|
||||
*/
|
||||
private void checkSubscriptions(IIdType idType, String resourceType, RestOperationTypeEnum theOperation) {
|
||||
for (Subscription subscription : myRestHookSubscriptions) {
|
||||
//avoid a ConcurrentModificationException by copying to an array
|
||||
for (Object object : myRestHookSubscriptions.toArray()) {
|
||||
if (object == null) {
|
||||
continue;
|
||||
}
|
||||
Subscription subscription = (Subscription) object;
|
||||
// see if the criteria matches the created object
|
||||
ourLog.info("Checking subscription {} for {} with criteria {}", subscription.getIdElement().getIdPart(), resourceType, subscription.getCriteria());
|
||||
|
||||
@ -117,6 +122,8 @@ public class RestHookSubscriptionDstu2Interceptor extends BaseRestHookSubscripti
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates an HTTP Post for a subscription
|
||||
*/
|
||||
|
@ -76,7 +76,13 @@ public class RestHookSubscriptionDstu3Interceptor extends BaseRestHookSubscripti
|
||||
* @param theOperation
|
||||
*/
|
||||
private void checkSubscriptions(IIdType idType, String resourceType, RestOperationTypeEnum theOperation) {
|
||||
for (Subscription subscription : myRestHookSubscriptions) {
|
||||
//avoid a ConcurrentModificationException by copying to an array
|
||||
for (Object object : myRestHookSubscriptions.toArray()) {
|
||||
//for (Subscription subscription : myRestHookSubscriptions) {
|
||||
if (object == null) {
|
||||
continue;
|
||||
}
|
||||
Subscription subscription = (Subscription) object;
|
||||
// see if the criteria matches the created object
|
||||
ourLog.info("Checking subscription {} for {} with criteria {}", subscription.getIdElement().getIdPart(), resourceType, subscription.getCriteria());
|
||||
|
||||
|
@ -27,8 +27,7 @@ import javax.persistence.criteria.*;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.TransactionCallback;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
import org.springframework.transaction.support.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.IDao;
|
||||
@ -103,16 +102,23 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
||||
return retVal;
|
||||
}
|
||||
|
||||
protected List<IBaseResource> doSearchOrEverythingInTransaction(final int theFromIndex, final int theToIndex) {
|
||||
ISearchBuilder sb = myDao.newSearchBuilder();
|
||||
protected List<IBaseResource> doSearchOrEverything(final int theFromIndex, final int theToIndex) {
|
||||
final ISearchBuilder sb = myDao.newSearchBuilder();
|
||||
|
||||
String resourceName = mySearchEntity.getResourceType();
|
||||
Class<? extends IBaseResource> resourceType = myContext.getResourceDefinition(resourceName).getImplementingClass();
|
||||
sb.setType(resourceType, resourceName);
|
||||
|
||||
List<Long> pidsSubList = mySearchCoordinatorSvc.getResources(myUuid, theFromIndex, theToIndex);
|
||||
final List<Long> pidsSubList = mySearchCoordinatorSvc.getResources(myUuid, theFromIndex, theToIndex);
|
||||
|
||||
return toResourceList(sb, pidsSubList);
|
||||
TransactionTemplate template = new TransactionTemplate(myPlatformTransactionManager);
|
||||
template.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRED);
|
||||
return template.execute(new TransactionCallback<List<IBaseResource>>() {
|
||||
@Override
|
||||
public List<IBaseResource> doInTransaction(TransactionStatus theStatus) {
|
||||
return toResourceList(sb, pidsSubList);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void ensureDependenciesInjected() {
|
||||
@ -165,22 +171,26 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
||||
|
||||
TransactionTemplate template = new TransactionTemplate(myPlatformTransactionManager);
|
||||
|
||||
return template.execute(new TransactionCallback<List<IBaseResource>>() {
|
||||
template.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
public List<IBaseResource> doInTransaction(TransactionStatus theStatus) {
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
|
||||
ensureSearchEntityLoaded();
|
||||
|
||||
switch (mySearchEntity.getSearchType()) {
|
||||
case HISTORY:
|
||||
return doHistoryInTransaction(theFromIndex, theToIndex);
|
||||
case SEARCH:
|
||||
case EVERYTHING:
|
||||
default:
|
||||
return doSearchOrEverythingInTransaction(theFromIndex, theToIndex);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
switch (mySearchEntity.getSearchType()) {
|
||||
case HISTORY:
|
||||
return template.execute(new TransactionCallback<List<IBaseResource>>() {
|
||||
@Override
|
||||
public List<IBaseResource> doInTransaction(TransactionStatus theStatus) {
|
||||
return doHistoryInTransaction(theFromIndex, theToIndex);
|
||||
}
|
||||
});
|
||||
case SEARCH:
|
||||
case EVERYTHING:
|
||||
default:
|
||||
return doSearchOrEverything(theFromIndex, theToIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public String getUuid() {
|
||||
|
@ -23,8 +23,6 @@ import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.transaction.Transactional;
|
||||
import javax.transaction.Transactional.TxType;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
@ -35,6 +33,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.*;
|
||||
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
|
||||
import org.springframework.transaction.*;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.*;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
@ -78,13 +78,13 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||
|
||||
private int mySyncSize = DEFAULT_SYNC_SIZE;
|
||||
|
||||
// @Autowired
|
||||
// private DataSource myDataSource;
|
||||
// @PostConstruct
|
||||
// public void start() {
|
||||
// JpaTransactionManager txManager = (JpaTransactionManager) myManagedTxManager;
|
||||
// }
|
||||
|
||||
// @Autowired
|
||||
// private DataSource myDataSource;
|
||||
// @PostConstruct
|
||||
// public void start() {
|
||||
// JpaTransactionManager txManager = (JpaTransactionManager) myManagedTxManager;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
@ -106,7 +106,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(value = TxType.NOT_SUPPORTED)
|
||||
@Transactional(propagation = Propagation.NEVER)
|
||||
public List<Long> getResources(final String theUuid, int theFrom, int theTo) {
|
||||
if (myNeverUseLocalSearchForUnitTests == false) {
|
||||
SearchTask task = myIdToSearchTask.get(theUuid);
|
||||
@ -116,7 +116,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||
}
|
||||
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||
|
||||
Search search;
|
||||
StopWatch sw = new StopWatch();
|
||||
@ -186,9 +186,9 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBundleProvider registerSearch(final IDao theCallingDao, SearchParameterMap theParams, String theResourceType) {
|
||||
public IBundleProvider registerSearch(final IDao theCallingDao, final SearchParameterMap theParams, String theResourceType) {
|
||||
StopWatch w = new StopWatch();
|
||||
String searchUuid = UUID.randomUUID().toString();
|
||||
final String searchUuid = UUID.randomUUID().toString();
|
||||
|
||||
Class<? extends IBaseResource> resourceTypeClass = myContext.getResourceDefinition(theResourceType).getImplementingClass();
|
||||
final ISearchBuilder sb = theCallingDao.newSearchBuilder();
|
||||
@ -196,36 +196,37 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||
|
||||
if (theParams.isLoadSynchronous()) {
|
||||
|
||||
// Load the results synchronously
|
||||
final List<Long> pids = new ArrayList<Long>();
|
||||
|
||||
Iterator<Long> resultIter = sb.createQuery(theParams, searchUuid);
|
||||
while (resultIter.hasNext()) {
|
||||
pids.add(resultIter.next());
|
||||
if (theParams.getLoadSynchronousUpTo() != null && pids.size() >= theParams.getLoadSynchronousUpTo()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For synchronous queries, we load all the includes right away
|
||||
* since we're returning a static bundle with all the results
|
||||
* pre-loaded. This is ok because syncronous requests are not
|
||||
* expected to be paged
|
||||
*
|
||||
* On the other hand for async queries we load includes/revincludes
|
||||
* individually for pages as we return them to clients
|
||||
*/
|
||||
final Set<Long> includedPids = new HashSet<Long>();
|
||||
includedPids.addAll(sb.loadReverseIncludes(theCallingDao, myContext, myEntityManager, pids, theParams.getRevIncludes(), true, theParams.getLastUpdated()));
|
||||
includedPids.addAll(sb.loadReverseIncludes(theCallingDao, myContext, myEntityManager, pids, theParams.getIncludes(), false, theParams.getLastUpdated()));
|
||||
|
||||
// Execute the query and make sure we return distinct results
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
||||
txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRED);
|
||||
return txTemplate.execute(new TransactionCallback<SimpleBundleProvider>() {
|
||||
@Override
|
||||
public SimpleBundleProvider doInTransaction(TransactionStatus theStatus) {
|
||||
|
||||
// Load the results synchronously
|
||||
final List<Long> pids = new ArrayList<Long>();
|
||||
|
||||
Iterator<Long> resultIter = sb.createQuery(theParams, searchUuid);
|
||||
while (resultIter.hasNext()) {
|
||||
pids.add(resultIter.next());
|
||||
if (theParams.getLoadSynchronousUpTo() != null && pids.size() >= theParams.getLoadSynchronousUpTo()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For synchronous queries, we load all the includes right away
|
||||
* since we're returning a static bundle with all the results
|
||||
* pre-loaded. This is ok because syncronous requests are not
|
||||
* expected to be paged
|
||||
*
|
||||
* On the other hand for async queries we load includes/revincludes
|
||||
* individually for pages as we return them to clients
|
||||
*/
|
||||
final Set<Long> includedPids = new HashSet<Long>();
|
||||
includedPids.addAll(sb.loadReverseIncludes(theCallingDao, myContext, myEntityManager, pids, theParams.getRevIncludes(), true, theParams.getLastUpdated()));
|
||||
includedPids.addAll(sb.loadReverseIncludes(theCallingDao, myContext, myEntityManager, pids, theParams.getIncludes(), false, theParams.getLastUpdated()));
|
||||
|
||||
List<IBaseResource> resources = new ArrayList<IBaseResource>();
|
||||
sb.loadResourcesByPid(pids, resources, includedPids, false, myEntityManager, myContext, theCallingDao);
|
||||
return new SimpleBundleProvider(resources);
|
||||
@ -441,7 +442,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||
|
||||
try {
|
||||
saveSearch();
|
||||
|
||||
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
||||
txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW);
|
||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@ -454,7 +455,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||
ourLog.info("Completed search for {} resources in {}ms", mySyncedPids.size(), sw.getMillis());
|
||||
|
||||
} catch (Throwable t) {
|
||||
|
||||
|
||||
/*
|
||||
* Don't print a stack trace for client errors.. that's just noisy
|
||||
*/
|
||||
@ -465,8 +466,8 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||
logged = true;
|
||||
ourLog.warn("Failed during search due to invalid request: {}", t.toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!logged) {
|
||||
ourLog.error("Failed during search loading after {}ms", sw.getMillis(), t);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package ca.uhn.fhir.jpa.search;
|
||||
|
||||
/*
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
@ -10,7 +10,7 @@ package ca.uhn.fhir.jpa.search;
|
||||
* 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
|
||||
* 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,
|
||||
@ -20,25 +20,24 @@ package ca.uhn.fhir.jpa.search;
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
import org.springframework.transaction.support.TransactionCallback;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchIncludeDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.*;
|
||||
import ca.uhn.fhir.jpa.entity.Search;
|
||||
|
||||
/**
|
||||
@ -47,7 +46,6 @@ import ca.uhn.fhir.jpa.entity.Search;
|
||||
public class StaleSearchDeletingSvcImpl implements IStaleSearchDeletingSvc {
|
||||
public static final long DEFAULT_CUTOFF_SLACK = 10 * DateUtils.MILLIS_PER_SECOND;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(StaleSearchDeletingSvcImpl.class);
|
||||
|
||||
|
||||
/*
|
||||
* We give a bit of extra leeway just to avoid race conditions where a query result
|
||||
@ -71,41 +69,48 @@ public class StaleSearchDeletingSvcImpl implements IStaleSearchDeletingSvc {
|
||||
@Autowired
|
||||
private PlatformTransactionManager myTransactionManager;
|
||||
|
||||
protected void deleteSearch(final Long theSearchPid) {
|
||||
TransactionTemplate tt = new TransactionTemplate(myTransactionManager);
|
||||
tt.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
Search searchToDelete = mySearchDao.findOne(theSearchPid);
|
||||
ourLog.info("Deleting search {}/{} - Created[{}] -- Last returned[{}]", searchToDelete.getId(), searchToDelete.getUuid(), searchToDelete.getCreated(), searchToDelete.getSearchLastReturned());
|
||||
mySearchIncludeDao.deleteForSearch(searchToDelete.getId());
|
||||
mySearchResultDao.deleteForSearch(searchToDelete.getId());
|
||||
mySearchDao.delete(searchToDelete);
|
||||
}
|
||||
});
|
||||
private void deleteSearch(final Long theSearchPid) {
|
||||
Search searchToDelete = mySearchDao.findOne(theSearchPid);
|
||||
ourLog.info("Deleting search {}/{} - Created[{}] -- Last returned[{}]", searchToDelete.getId(), searchToDelete.getUuid(), searchToDelete.getCreated(), searchToDelete.getSearchLastReturned());
|
||||
mySearchIncludeDao.deleteForSearch(searchToDelete.getId());
|
||||
mySearchResultDao.deleteForSearch(searchToDelete.getId());
|
||||
mySearchDao.delete(searchToDelete);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(propagation = Propagation.NOT_SUPPORTED)
|
||||
public void pollForStaleSearchesAndDeleteThem() {
|
||||
|
||||
|
||||
long cutoffMillis = myDaoConfig.getExpireSearchResultsAfterMillis();
|
||||
if (myDaoConfig.getReuseCachedSearchResultsForMillis() != null) {
|
||||
cutoffMillis = Math.max(cutoffMillis, myDaoConfig.getReuseCachedSearchResultsForMillis());
|
||||
}
|
||||
Date cutoff = new Date((System.currentTimeMillis() - cutoffMillis) - myCutoffSlack);
|
||||
|
||||
final Date cutoff = new Date((System.currentTimeMillis() - cutoffMillis) - myCutoffSlack);
|
||||
|
||||
ourLog.debug("Searching for searches which are before {}", cutoff);
|
||||
|
||||
Collection<Long> toDelete = mySearchDao.findWhereLastReturnedBefore(cutoff);
|
||||
if (!toDelete.isEmpty()) {
|
||||
|
||||
for (final Long next : toDelete) {
|
||||
deleteSearch(next);
|
||||
TransactionTemplate tt = new TransactionTemplate(myTransactionManager);
|
||||
int count = tt.execute(new TransactionCallback<Integer>() {
|
||||
@Override
|
||||
public Integer doInTransaction(TransactionStatus theStatus) {
|
||||
Slice<Long> toDelete = mySearchDao.findWhereLastReturnedBefore(cutoff, new PageRequest(0, 1000));
|
||||
for (final Long next : toDelete) {
|
||||
deleteSearch(next);
|
||||
}
|
||||
return toDelete.getContent().size();
|
||||
}
|
||||
});
|
||||
|
||||
ourLog.info("Deleted {} searches, {} remaining", toDelete.size(), mySearchDao.count());
|
||||
if (count > 0) {
|
||||
long total = tt.execute(new TransactionCallback<Long>() {
|
||||
@Override
|
||||
public Long doInTransaction(TransactionStatus theStatus) {
|
||||
return mySearchDao.count();
|
||||
}
|
||||
});
|
||||
ourLog.info("Deleted {} searches, {} remaining", count, total);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Scheduled(fixedDelay = DEFAULT_CUTOFF_SLACK)
|
||||
|
@ -10,7 +10,7 @@ package ca.uhn.fhir.jpa.term;
|
||||
* 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
|
||||
* 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,
|
||||
@ -19,21 +19,10 @@ package ca.uhn.fhir.jpa.term;
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
import javax.persistence.PersistenceContextType;
|
||||
import javax.persistence.*;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
@ -51,19 +40,12 @@ import org.springframework.transaction.support.TransactionTemplate;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Multimaps;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemVersionDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.ITermConceptDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.ITermConceptParentChildLinkDao;
|
||||
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
|
||||
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
|
||||
import ca.uhn.fhir.jpa.dao.data.*;
|
||||
import ca.uhn.fhir.jpa.entity.*;
|
||||
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
|
||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
@ -76,6 +58,8 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiTerminologySvc.class);
|
||||
private static final Object PLACEHOLDER_OBJECT = new Object();
|
||||
|
||||
private ArrayListMultimap<Long, Long> myChildToParentPidCache;
|
||||
|
||||
@Autowired
|
||||
protected ITermCodeSystemDao myCodeSystemDao;
|
||||
|
||||
@ -100,8 +84,8 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||
|
||||
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
|
||||
protected EntityManager myEntityManager;
|
||||
|
||||
private long myNextReindexPass;
|
||||
|
||||
private boolean myProcessDeferred = true;
|
||||
|
||||
@Autowired
|
||||
@ -121,7 +105,7 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||
private int ensureParentsSaved(Collection<TermConceptParentChildLink> theParents) {
|
||||
ourLog.trace("Checking {} parents", theParents.size());
|
||||
int retVal = 0;
|
||||
|
||||
|
||||
for (TermConceptParentChildLink nextLink : theParents) {
|
||||
if (nextLink.getRelationshipType() == RelationshipTypeEnum.ISA) {
|
||||
TermConcept nextParent = nextLink.getParent();
|
||||
@ -133,7 +117,7 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@ -206,8 +190,11 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||
|
||||
/**
|
||||
* Subclasses may override
|
||||
* @param theSystem The code system
|
||||
* @param theCode The code
|
||||
*
|
||||
* @param theSystem
|
||||
* The code system
|
||||
* @param theCode
|
||||
* The code
|
||||
*/
|
||||
protected List<VersionIndependentConcept> findCodesAboveUsingBuiltInSystems(String theSystem, String theCode) {
|
||||
return Collections.emptyList();
|
||||
@ -244,15 +231,19 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||
ArrayList<VersionIndependentConcept> retVal = toVersionIndependentConcepts(theSystem, codes);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may override
|
||||
* @param theSystem The code system
|
||||
* @param theCode The code
|
||||
*
|
||||
* @param theSystem
|
||||
* The code system
|
||||
* @param theCode
|
||||
* The code
|
||||
*/
|
||||
protected List<VersionIndependentConcept> findCodesBelowUsingBuiltInSystems(String theSystem, String theCode) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
|
||||
private TermCodeSystemVersion findCurrentCodeSystemVersionForSystem(String theCodeSystem) {
|
||||
TermCodeSystem cs = getCodeSystem(theCodeSystem);
|
||||
if (cs == null || cs.getCurrentVersion() == null) {
|
||||
@ -274,7 +265,7 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||
|
||||
if (theConceptsStack.size() == 1 || theConceptsStack.size() % 10000 == 0) {
|
||||
float pct = (float) theConceptsStack.size() / (float) theTotalConcepts;
|
||||
ourLog.info("Have processed {}/{} concepts ({}%)", theConceptsStack.size(), theTotalConcepts, (int)( pct*100.0f));
|
||||
ourLog.info("Have processed {}/{} concepts ({}%)", theConceptsStack.size(), theTotalConcepts, (int) (pct * 100.0f));
|
||||
}
|
||||
|
||||
theConcept.setCodeSystem(theCodeSystem);
|
||||
@ -285,7 +276,7 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||
} else {
|
||||
myConceptsToSaveLater.add(theConcept);
|
||||
}
|
||||
|
||||
|
||||
for (TermConceptParentChildLink next : theConcept.getChildren()) {
|
||||
persistChildren(next.getChild(), theCodeSystem, theConceptsStack, theTotalConcepts);
|
||||
}
|
||||
@ -297,7 +288,7 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||
myConceptLinksToSaveLater.add(next);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void populateVersion(TermConcept theNext, TermCodeSystemVersion theCodeSystemVersion) {
|
||||
@ -310,48 +301,56 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||
}
|
||||
}
|
||||
|
||||
private ArrayListMultimap<Long, Long> myChildToParentPidCache;
|
||||
|
||||
private void processDeferredConcepts() {
|
||||
int codeCount = 0, relCount = 0;
|
||||
StopWatch stopwatch = new StopWatch();
|
||||
|
||||
int count = Math.min(myDaoConfig.getDeferIndexingForCodesystemsOfSize(), myConceptsToSaveLater.size());
|
||||
ourLog.info("Saving {} deferred concepts...", count);
|
||||
while (codeCount < count && myConceptsToSaveLater.size() > 0) {
|
||||
TermConcept next = myConceptsToSaveLater.remove(0);
|
||||
codeCount += saveConcept(next);
|
||||
}
|
||||
|
||||
if (codeCount > 0) {
|
||||
ourLog.info("Saved {} deferred concepts ({} codes remain and {} relationships remain) in {}ms ({}ms / code)",
|
||||
new Object[] { codeCount, myConceptsToSaveLater.size(), myConceptLinksToSaveLater.size(), stopwatch.getMillis(), stopwatch.getMillisPerOperation(codeCount) });
|
||||
}
|
||||
|
||||
if (codeCount == 0) {
|
||||
count = Math.min(myDaoConfig.getDeferIndexingForCodesystemsOfSize(), myConceptLinksToSaveLater.size());
|
||||
ourLog.info("Saving {} deferred concept relationships...", count);
|
||||
while (relCount < count && myConceptLinksToSaveLater.size() > 0) {
|
||||
TermConceptParentChildLink next = myConceptLinksToSaveLater.remove(0);
|
||||
|
||||
if (myConceptDao.findOne(next.getChild().getId()) == null || myConceptDao.findOne(next.getParent().getId()) == null) {
|
||||
ourLog.warn("Not inserting link from child {} to parent {} because it appears to have been deleted", next.getParent().getCode(), next.getChild().getCode());
|
||||
continue;
|
||||
}
|
||||
|
||||
saveConceptLink(next);
|
||||
relCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (relCount > 0) {
|
||||
ourLog.info("Saved {} deferred relationships ({} remain) in {}ms ({}ms / code)",
|
||||
new Object[] { relCount, myConceptLinksToSaveLater.size(), stopwatch.getMillis(), stopwatch.getMillisPerOperation(codeCount) });
|
||||
}
|
||||
|
||||
if ((myConceptsToSaveLater.size() + myConceptLinksToSaveLater.size()) == 0) {
|
||||
ourLog.info("All deferred concepts and relationships have now been synchronized to the database");
|
||||
}
|
||||
}
|
||||
|
||||
private void processReindexing() {
|
||||
if (System.currentTimeMillis() < myNextReindexPass && !ourForceSaveDeferredAlwaysForUnitTest) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
TransactionTemplate tt = new TransactionTemplate(myTransactionMgr);
|
||||
tt.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW);
|
||||
tt.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
int maxResult = 1000;
|
||||
Page<TermConcept> concepts = myConceptDao.findResourcesRequiringReindexing(new PageRequest(0, maxResult));
|
||||
if (concepts.hasContent() == false) {
|
||||
myNextReindexPass = System.currentTimeMillis() + DateUtils.MILLIS_PER_MINUTE;
|
||||
myChildToParentPidCache = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (myChildToParentPidCache == null) {
|
||||
myChildToParentPidCache = ArrayListMultimap.create();
|
||||
}
|
||||
|
||||
ourLog.info("Indexing {} / {} concepts", concepts.getContent().size(), concepts.getTotalElements());
|
||||
|
||||
int count = 0;
|
||||
StopWatch stopwatch = new StopWatch();
|
||||
|
||||
for (TermConcept nextConcept : concepts) {
|
||||
|
||||
StringBuilder parentsBuilder = new StringBuilder();
|
||||
createParentsString(parentsBuilder, nextConcept.getId());
|
||||
nextConcept.setParentPids(parentsBuilder.toString());
|
||||
|
||||
saveConcept(nextConcept);
|
||||
count++;
|
||||
}
|
||||
|
||||
ourLog.info("Indexed {} / {} concepts in {}ms - Avg {}ms / resource", new Object[] { count, concepts.getContent().size(), stopwatch.getMillis(), stopwatch.getMillisPerOperation(count) });
|
||||
}
|
||||
|
||||
private void createParentsString(StringBuilder theParentsBuilder, Long theConceptPid) {
|
||||
Validate.notNull(theConceptPid, "theConceptPid must not be null");
|
||||
List<Long> parents = myChildToParentPidCache.get(theConceptPid);
|
||||
@ -368,8 +367,7 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (Long nextParent : parents) {
|
||||
if (theParentsBuilder.length() > 0) {
|
||||
theParentsBuilder.append(' ');
|
||||
@ -378,13 +376,45 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||
createParentsString(theParentsBuilder, nextParent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
int maxResult = 1000;
|
||||
Page<TermConcept> concepts = myConceptDao.findResourcesRequiringReindexing(new PageRequest(0, maxResult));
|
||||
if (concepts.hasContent() == false) {
|
||||
myNextReindexPass = System.currentTimeMillis() + DateUtils.MILLIS_PER_MINUTE;
|
||||
myChildToParentPidCache = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (myChildToParentPidCache == null) {
|
||||
myChildToParentPidCache = ArrayListMultimap.create();
|
||||
}
|
||||
|
||||
ourLog.info("Indexing {} / {} concepts", concepts.getContent().size(), concepts.getTotalElements());
|
||||
|
||||
int count = 0;
|
||||
StopWatch stopwatch = new StopWatch();
|
||||
|
||||
for (TermConcept nextConcept : concepts) {
|
||||
|
||||
StringBuilder parentsBuilder = new StringBuilder();
|
||||
createParentsString(parentsBuilder, nextConcept.getId());
|
||||
nextConcept.setParentPids(parentsBuilder.toString());
|
||||
|
||||
saveConcept(nextConcept);
|
||||
count++;
|
||||
}
|
||||
|
||||
ourLog.info("Indexed {} / {} concepts in {}ms - Avg {}ms / resource", new Object[] { count, concepts.getContent().size(), stopwatch.getMillis(), stopwatch.getMillisPerOperation(count) });
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private int saveConcept(TermConcept theConcept) {
|
||||
int retVal = 0;
|
||||
|
||||
|
||||
/*
|
||||
* If the concept has an ID, we're reindexing, so there's no need to
|
||||
* save parent concepts first (it's way too slow to do that)
|
||||
@ -392,25 +422,25 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||
if (theConcept.getId() == null) {
|
||||
retVal += ensureParentsSaved(theConcept.getParents());
|
||||
}
|
||||
|
||||
|
||||
if (theConcept.getId() == null || theConcept.getIndexStatus() == null) {
|
||||
retVal++;
|
||||
theConcept.setIndexStatus(BaseHapiFhirDao.INDEX_STATUS_INDEXED);
|
||||
myConceptDao.save(theConcept);
|
||||
}
|
||||
|
||||
|
||||
ourLog.trace("Saved {} and got PID {}", theConcept.getCode(), theConcept.getId());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
private void saveConceptLink(TermConceptParentChildLink next) {
|
||||
if (next.getId() == null) {
|
||||
myConceptParentChildLinkDao.save(next);
|
||||
}
|
||||
}
|
||||
|
||||
@Scheduled(fixedRate=5000)
|
||||
@Transactional(propagation=Propagation.REQUIRED)
|
||||
@Scheduled(fixedRate = 5000)
|
||||
@Transactional(propagation = Propagation.NEVER)
|
||||
@Override
|
||||
public synchronized void saveDeferred() {
|
||||
if (!myProcessDeferred) {
|
||||
@ -419,46 +449,18 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||
processReindexing();
|
||||
return;
|
||||
}
|
||||
|
||||
int codeCount = 0, relCount = 0;
|
||||
StopWatch stopwatch = new StopWatch();
|
||||
|
||||
int count = Math.min(myDaoConfig.getDeferIndexingForCodesystemsOfSize(), myConceptsToSaveLater.size());
|
||||
ourLog.info("Saving {} deferred concepts...", count);
|
||||
while (codeCount < count && myConceptsToSaveLater.size() > 0) {
|
||||
TermConcept next = myConceptsToSaveLater.remove(0);
|
||||
codeCount += saveConcept(next);
|
||||
}
|
||||
|
||||
if (codeCount > 0) {
|
||||
ourLog.info("Saved {} deferred concepts ({} codes remain and {} relationships remain) in {}ms ({}ms / code)", new Object[] {codeCount, myConceptsToSaveLater.size(), myConceptLinksToSaveLater.size(), stopwatch.getMillis(), stopwatch.getMillisPerOperation(codeCount)});
|
||||
}
|
||||
|
||||
if (codeCount == 0) {
|
||||
count = Math.min(myDaoConfig.getDeferIndexingForCodesystemsOfSize(), myConceptLinksToSaveLater.size());
|
||||
ourLog.info("Saving {} deferred concept relationships...", count);
|
||||
while (relCount < count && myConceptLinksToSaveLater.size() > 0) {
|
||||
TermConceptParentChildLink next = myConceptLinksToSaveLater.remove(0);
|
||||
|
||||
if (myConceptDao.findOne(next.getChild().getId()) == null || myConceptDao.findOne(next.getParent().getId()) == null) {
|
||||
ourLog.warn("Not inserting link from child {} to parent {} because it appears to have been deleted", next.getParent().getCode(), next.getChild().getCode());
|
||||
continue;
|
||||
}
|
||||
|
||||
saveConceptLink(next);
|
||||
relCount++;
|
||||
TransactionTemplate tt = new TransactionTemplate(myTransactionMgr);
|
||||
tt.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW);
|
||||
tt.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
processDeferredConcepts();
|
||||
}
|
||||
}
|
||||
|
||||
if (relCount > 0) {
|
||||
ourLog.info("Saved {} deferred relationships ({} remain) in {}ms ({}ms / code)", new Object[] {relCount, myConceptLinksToSaveLater.size(), stopwatch.getMillis(), stopwatch.getMillisPerOperation(codeCount)});
|
||||
}
|
||||
|
||||
if ((myConceptsToSaveLater.size() + myConceptLinksToSaveLater.size()) == 0) {
|
||||
ourLog.info("All deferred concepts and relationships have now been synchronized to the database");
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setProcessDeferred(boolean theProcessDeferred) {
|
||||
myProcessDeferred = theProcessDeferred;
|
||||
@ -487,7 +489,7 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||
}
|
||||
|
||||
ourLog.info("Flushing...");
|
||||
|
||||
|
||||
myConceptParentChildLinkDao.flush();
|
||||
myConceptDao.flush();
|
||||
|
||||
@ -540,7 +542,7 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||
}
|
||||
|
||||
ourLog.info("Saving {} concepts...", totalCodeCount);
|
||||
|
||||
|
||||
IdentityHashMap<TermConcept, Object> conceptsStack2 = new IdentityHashMap<TermConcept, Object>();
|
||||
for (TermConcept next : theCodeSystemVersion.getConcepts()) {
|
||||
persistChildren(next, codeSystemVersion, conceptsStack2, totalCodeCount);
|
||||
@ -552,7 +554,7 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||
myConceptParentChildLinkDao.flush();
|
||||
|
||||
ourLog.info("Done deleting old code system versions");
|
||||
|
||||
|
||||
if (myConceptsToSaveLater.size() > 0 || myConceptLinksToSaveLater.size() > 0) {
|
||||
ourLog.info("Note that some concept saving was deferred - still have {} concepts and {} relationships", myConceptsToSaveLater.size(), myConceptLinksToSaveLater.size());
|
||||
}
|
||||
@ -563,7 +565,7 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||
TermCodeSystem cs = getCodeSystem(theSystem);
|
||||
return cs != null;
|
||||
}
|
||||
|
||||
|
||||
private ArrayList<VersionIndependentConcept> toVersionIndependentConcepts(String theSystem, Set<TermConcept> codes) {
|
||||
ArrayList<VersionIndependentConcept> retVal = new ArrayList<VersionIndependentConcept>(codes.size());
|
||||
for (TermConcept next : codes) {
|
||||
@ -582,7 +584,7 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
|
||||
throw new InvalidRequestException("CodeSystem contains circular reference around code " + theConcept.getCode());
|
||||
}
|
||||
theConceptsStack.add(theConcept.getCode());
|
||||
|
||||
|
||||
int retVal = 0;
|
||||
if (theAllConcepts.put(theConcept, theAllConcepts) == null) {
|
||||
if (theAllConcepts.size() % 1000 == 0) {
|
||||
|
@ -29,8 +29,8 @@ import org.hibernate.search.jpa.FullTextEntityManager;
|
||||
import org.hibernate.search.jpa.FullTextQuery;
|
||||
import org.hibernate.search.query.dsl.BooleanJunction;
|
||||
import org.hibernate.search.query.dsl.QueryBuilder;
|
||||
import org.hl7.fhir.r4.hapi.validation.HapiWorkerContext;
|
||||
import org.hl7.fhir.r4.hapi.validation.IValidationSupport;
|
||||
import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext;
|
||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode;
|
||||
import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
|
||||
|
@ -1,26 +1,6 @@
|
||||
package ca.uhn.fhir.jpa.term;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2017 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.hl7.fhir.r4.hapi.validation.IValidationSupport;
|
||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||
|
||||
public interface IHapiTerminologySvcR4 extends IHapiTerminologySvc, IValidationSupport {
|
||||
// nothing
|
||||
|
@ -0,0 +1,12 @@
|
||||
package ca.uhn.fhir.jpa.util;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
public abstract class BaseIterator<T> implements Iterator<T> {
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
@ -23,8 +23,8 @@ package ca.uhn.fhir.jpa.validation;
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import org.hl7.fhir.r4.hapi.validation.DefaultProfileValidationSupport;
|
||||
import org.hl7.fhir.r4.hapi.validation.ValidationSupportChain;
|
||||
import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport;
|
||||
import org.hl7.fhir.r4.hapi.ctx.ValidationSupportChain;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
|
@ -0,0 +1,289 @@
|
||||
package ca.uhn.fhir.jpa.config;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class ConnectionWrapper implements Connection {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ConnectionWrapper.class);
|
||||
|
||||
private Connection myWrap;
|
||||
|
||||
public ConnectionWrapper(Connection theConnection) {
|
||||
myWrap = theConnection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort(Executor theExecutor) throws SQLException {
|
||||
myWrap.abort(theExecutor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearWarnings() throws SQLException {
|
||||
myWrap.clearWarnings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws SQLException {
|
||||
// ourLog.info("** Closing connection");
|
||||
myWrap.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit() throws SQLException {
|
||||
myWrap.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Array createArrayOf(String theTypeName, Object[] theElements) throws SQLException {
|
||||
return myWrap.createArrayOf(theTypeName, theElements);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Blob createBlob() throws SQLException {
|
||||
return myWrap.createBlob();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Clob createClob() throws SQLException {
|
||||
return myWrap.createClob();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NClob createNClob() throws SQLException {
|
||||
return myWrap.createNClob();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLXML createSQLXML() throws SQLException {
|
||||
return myWrap.createSQLXML();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement createStatement() throws SQLException {
|
||||
return myWrap.createStatement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement createStatement(int theResultSetType, int theResultSetConcurrency) throws SQLException {
|
||||
return myWrap.createStatement(theResultSetType, theResultSetConcurrency);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement createStatement(int theResultSetType, int theResultSetConcurrency, int theResultSetHoldability) throws SQLException {
|
||||
return myWrap.createStatement(theResultSetType, theResultSetConcurrency, theResultSetHoldability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Struct createStruct(String theTypeName, Object[] theAttributes) throws SQLException {
|
||||
return myWrap.createStruct(theTypeName, theAttributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getAutoCommit() throws SQLException {
|
||||
return myWrap.getAutoCommit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCatalog() throws SQLException {
|
||||
return myWrap.getCatalog();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties getClientInfo() throws SQLException {
|
||||
return myWrap.getClientInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientInfo(String theName) throws SQLException {
|
||||
return getClientInfo(theName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHoldability() throws SQLException {
|
||||
return myWrap.getHoldability();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DatabaseMetaData getMetaData() throws SQLException {
|
||||
return myWrap.getMetaData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNetworkTimeout() throws SQLException {
|
||||
return myWrap.getNetworkTimeout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSchema() throws SQLException {
|
||||
return myWrap.getSchema();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTransactionIsolation() throws SQLException {
|
||||
return myWrap.getTransactionIsolation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Class<?>> getTypeMap() throws SQLException {
|
||||
return myWrap.getTypeMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLWarning getWarnings() throws SQLException {
|
||||
return myWrap.getWarnings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() throws SQLException {
|
||||
return myWrap.isClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() throws SQLException {
|
||||
return myWrap.isReadOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(int theTimeout) throws SQLException {
|
||||
return myWrap.isValid(theTimeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWrapperFor(Class<?> theIface) throws SQLException {
|
||||
return myWrap.isWrapperFor(theIface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String nativeSQL(String theSql) throws SQLException {
|
||||
return myWrap.nativeSQL(theSql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallableStatement prepareCall(String theSql) throws SQLException {
|
||||
return myWrap.prepareCall(theSql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallableStatement prepareCall(String theSql, int theResultSetType, int theResultSetConcurrency) throws SQLException {
|
||||
return myWrap.prepareCall(theSql, theResultSetType, theResultSetConcurrency);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallableStatement prepareCall(String theSql, int theResultSetType, int theResultSetConcurrency, int theResultSetHoldability) throws SQLException {
|
||||
return myWrap.prepareCall(theSql, theResultSetType, theResultSetConcurrency, theResultSetHoldability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String theSql) throws SQLException {
|
||||
return myWrap.prepareStatement(theSql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String theSql, int theAutoGeneratedKeys) throws SQLException {
|
||||
return myWrap.prepareStatement(theSql, theAutoGeneratedKeys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String theSql, int theResultSetType, int theResultSetConcurrency) throws SQLException {
|
||||
return myWrap.prepareStatement(theSql, theResultSetType, theResultSetConcurrency);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String theSql, int theResultSetType, int theResultSetConcurrency, int theResultSetHoldability) throws SQLException {
|
||||
return myWrap.prepareStatement(theSql, theResultSetType, theResultSetConcurrency, theResultSetHoldability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String theSql, int[] theColumnIndexes) throws SQLException {
|
||||
return myWrap.prepareStatement(theSql, theColumnIndexes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String theSql, String[] theColumnNames) throws SQLException {
|
||||
return myWrap.prepareStatement(theSql, theColumnNames);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseSavepoint(Savepoint theSavepoint) throws SQLException {
|
||||
myWrap.releaseSavepoint(theSavepoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback() throws SQLException {
|
||||
myWrap.rollback();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback(Savepoint theSavepoint) throws SQLException {
|
||||
myWrap.rollback(theSavepoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAutoCommit(boolean theAutoCommit) throws SQLException {
|
||||
myWrap.setAutoCommit(theAutoCommit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCatalog(String theCatalog) throws SQLException {
|
||||
myWrap.setCatalog(theCatalog);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientInfo(Properties theProperties) throws SQLClientInfoException {
|
||||
myWrap.setClientInfo(theProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientInfo(String theName, String theValue) throws SQLClientInfoException {
|
||||
myWrap.setClientInfo(theName, theValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHoldability(int theHoldability) throws SQLException {
|
||||
myWrap.setHoldability(theHoldability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNetworkTimeout(Executor theExecutor, int theMilliseconds) throws SQLException {
|
||||
myWrap.setNetworkTimeout(theExecutor, theMilliseconds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadOnly(boolean theReadOnly) throws SQLException {
|
||||
myWrap.setReadOnly(theReadOnly);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Savepoint setSavepoint() throws SQLException {
|
||||
return myWrap.setSavepoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Savepoint setSavepoint(String theName) throws SQLException {
|
||||
return myWrap.setSavepoint(theName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSchema(String theSchema) throws SQLException {
|
||||
myWrap.setSchema(theSchema);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTransactionIsolation(int theLevel) throws SQLException {
|
||||
myWrap.setTransactionIsolation(theLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTypeMap(Map<String, Class<?>> theMap) throws SQLException {
|
||||
myWrap.setTypeMap(theMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> theIface) throws SQLException {
|
||||
return myWrap.unwrap(theIface);
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package ca.uhn.fhir.jpa.config;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@ -8,9 +10,7 @@ import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.*;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
@ -18,30 +18,82 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import net.ttddyy.dsproxy.listener.logging.SLF4JLogLevel;
|
||||
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
|
||||
|
||||
@Configuration
|
||||
@EnableTransactionManagement()
|
||||
public class TestDstu3Config extends BaseJavaConfigDstu3 {
|
||||
|
||||
static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TestDstu3Config.class);
|
||||
|
||||
@Bean()
|
||||
public DaoConfig daoConfig() {
|
||||
return new DaoConfig();
|
||||
}
|
||||
|
||||
private Exception myLastStackTrace;
|
||||
|
||||
@Bean()
|
||||
public DataSource dataSource() {
|
||||
BasicDataSource retVal = new BasicDataSource();
|
||||
BasicDataSource retVal = new BasicDataSource() {
|
||||
|
||||
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
ConnectionWrapper retVal;
|
||||
try {
|
||||
retVal = new ConnectionWrapper(super.getConnection());
|
||||
} catch (Exception e) {
|
||||
ourLog.error("Exceeded maximum wait for connection", e);
|
||||
logGetConnectionStackTrace();
|
||||
System.exit(1);
|
||||
retVal = null;
|
||||
}
|
||||
|
||||
try {
|
||||
throw new Exception();
|
||||
} catch (Exception e) {
|
||||
myLastStackTrace = e;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private void logGetConnectionStackTrace() {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("Last connection request stack trace:");
|
||||
for (StackTraceElement next : myLastStackTrace.getStackTrace()) {
|
||||
b.append("\n ");
|
||||
b.append(next.getClassName());
|
||||
b.append(".");
|
||||
b.append(next.getMethodName());
|
||||
b.append("(");
|
||||
b.append(next.getFileName());
|
||||
b.append(":");
|
||||
b.append(next.getLineNumber());
|
||||
b.append(")");
|
||||
}
|
||||
ourLog.info(b.toString());
|
||||
}
|
||||
|
||||
};
|
||||
retVal.setDriver(new org.apache.derby.jdbc.EmbeddedDriver());
|
||||
retVal.setUrl("jdbc:derby:memory:myUnitTestDB;create=true");
|
||||
retVal.setMaxWaitMillis(10000);
|
||||
retVal.setUsername("");
|
||||
retVal.setPassword("");
|
||||
retVal.setMaxTotal(4);
|
||||
|
||||
/*
|
||||
* We use a randomized number of maximum threads in order to try
|
||||
* and catch any potential deadlocks caused by database connection
|
||||
* starvation
|
||||
*/
|
||||
int maxThreads = (int) (Math.random() * 6) + 1;
|
||||
retVal.setMaxTotal(maxThreads);
|
||||
|
||||
DataSource dataSource = ProxyDataSourceBuilder
|
||||
.create(retVal)
|
||||
.logQueryBySlf4j(SLF4JLogLevel.INFO, "SQL")
|
||||
// .logQueryBySlf4j(SLF4JLogLevel.INFO, "SQL")
|
||||
.logSlowQueryBySlf4j(10, TimeUnit.SECONDS)
|
||||
.countQuery()
|
||||
.build();
|
||||
@ -49,13 +101,6 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
@Bean()
|
||||
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
|
||||
JpaTransactionManager retVal = new JpaTransactionManager();
|
||||
retVal.setEntityManagerFactory(entityManagerFactory);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean()
|
||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
|
||||
@ -95,4 +140,11 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
|
||||
return requestValidator;
|
||||
}
|
||||
|
||||
@Bean()
|
||||
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
|
||||
JpaTransactionManager retVal = new JpaTransactionManager();
|
||||
retVal.setEntityManagerFactory(entityManagerFactory);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ import java.util.*;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.*;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryRequestComponent;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryResponseComponent;
|
||||
@ -170,6 +169,74 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBatchCreateWithBadRead() {
|
||||
Bundle request = new Bundle();
|
||||
request.setType(BundleType.BATCH);
|
||||
|
||||
Patient p;
|
||||
p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system").setValue("FOO");
|
||||
request
|
||||
.addEntry()
|
||||
.setResource(p)
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.POST)
|
||||
.setUrl("Patient");
|
||||
|
||||
request
|
||||
.addEntry()
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.GET)
|
||||
.setUrl("Patient/BABABABA");
|
||||
|
||||
Bundle response = mySystemDao.transaction(mySrd, request);
|
||||
assertEquals(2, response.getEntry().size());
|
||||
|
||||
assertEquals("201 Created", response.getEntry().get(0).getResponse().getStatus());
|
||||
assertThat(response.getEntry().get(0).getResponse().getLocation(), matchesPattern(".*Patient/[0-9]+.*"));
|
||||
assertEquals("404 Not Found", response.getEntry().get(1).getResponse().getStatus());
|
||||
|
||||
OperationOutcome oo = (OperationOutcome) response.getEntry().get(1).getResponse().getOutcome();
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(oo));
|
||||
assertEquals(IssueSeverity.ERROR, oo.getIssue().get(0).getSeverity());
|
||||
assertEquals("Resource Patient/BABABABA is not known", oo.getIssue().get(0).getDiagnostics());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBatchCreateWithBadSearch() {
|
||||
Bundle request = new Bundle();
|
||||
request.setType(BundleType.BATCH);
|
||||
|
||||
Patient p;
|
||||
p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system").setValue("FOO");
|
||||
request
|
||||
.addEntry()
|
||||
.setResource(p)
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.POST)
|
||||
.setUrl("Patient");
|
||||
|
||||
request
|
||||
.addEntry()
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.GET)
|
||||
.setUrl("Patient?foobadparam=1");
|
||||
|
||||
Bundle response = mySystemDao.transaction(mySrd, request);
|
||||
assertEquals(2, response.getEntry().size());
|
||||
|
||||
assertEquals("201 Created", response.getEntry().get(0).getResponse().getStatus());
|
||||
assertThat(response.getEntry().get(0).getResponse().getLocation(), matchesPattern(".*Patient/[0-9]+.*"));
|
||||
assertEquals("400 Bad Request", response.getEntry().get(1).getResponse().getStatus());
|
||||
|
||||
OperationOutcome oo = (OperationOutcome) response.getEntry().get(1).getResponse().getOutcome();
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(oo));
|
||||
assertEquals(IssueSeverity.ERROR, oo.getIssue().get(0).getSeverity());
|
||||
assertThat(oo.getIssue().get(0).getDiagnostics(), containsString("Unknown search parameter"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCircularCreateAndDelete() {
|
||||
Encounter enc = new Encounter();
|
||||
@ -552,9 +619,10 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
||||
assertThat(resp.getEntry().get(0).getResponse().getLocation(), startsWith("Patient/"));
|
||||
|
||||
// Bundle.entry[1] is failed read response
|
||||
assertEquals(OperationOutcome.class, resp.getEntry().get(1).getResource().getClass());
|
||||
assertEquals(IssueSeverity.ERROR, ((OperationOutcome) resp.getEntry().get(1).getResource()).getIssue().get(0).getSeverityElement().getValue());
|
||||
assertEquals("Resource Patient/THIS_ID_DOESNT_EXIST is not known", ((OperationOutcome) resp.getEntry().get(1).getResource()).getIssue().get(0).getDiagnostics());
|
||||
Resource oo = resp.getEntry().get(1).getResponse().getOutcome();
|
||||
assertEquals(OperationOutcome.class, oo.getClass());
|
||||
assertEquals(IssueSeverity.ERROR, ((OperationOutcome) oo).getIssue().get(0).getSeverityElement().getValue());
|
||||
assertEquals("Resource Patient/THIS_ID_DOESNT_EXIST is not known", ((OperationOutcome) oo).getIssue().get(0).getDiagnostics());
|
||||
assertEquals("404 Not Found", resp.getEntry().get(1).getResponse().getStatus());
|
||||
|
||||
// Check POST
|
||||
@ -869,6 +937,74 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionCreateWithBadRead() {
|
||||
Bundle request = new Bundle();
|
||||
request.setType(BundleType.TRANSACTION);
|
||||
|
||||
Patient p;
|
||||
p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system").setValue("FOO");
|
||||
request
|
||||
.addEntry()
|
||||
.setResource(p)
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.POST)
|
||||
.setUrl("Patient");
|
||||
|
||||
request
|
||||
.addEntry()
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.GET)
|
||||
.setUrl("Patient/BABABABA");
|
||||
|
||||
Bundle response = mySystemDao.transaction(mySrd, request);
|
||||
assertEquals(2, response.getEntry().size());
|
||||
|
||||
assertEquals("201 Created", response.getEntry().get(0).getResponse().getStatus());
|
||||
assertThat(response.getEntry().get(0).getResponse().getLocation(), matchesPattern(".*Patient/[0-9]+.*"));
|
||||
assertEquals("404 Not Found", response.getEntry().get(1).getResponse().getStatus());
|
||||
|
||||
OperationOutcome oo = (OperationOutcome) response.getEntry().get(1).getResponse().getOutcome();
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(oo));
|
||||
assertEquals(IssueSeverity.ERROR, oo.getIssue().get(0).getSeverity());
|
||||
assertEquals("Resource Patient/BABABABA is not known", oo.getIssue().get(0).getDiagnostics());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionCreateWithBadSearch() {
|
||||
Bundle request = new Bundle();
|
||||
request.setType(BundleType.TRANSACTION);
|
||||
|
||||
Patient p;
|
||||
p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system").setValue("FOO");
|
||||
request
|
||||
.addEntry()
|
||||
.setResource(p)
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.POST)
|
||||
.setUrl("Patient");
|
||||
|
||||
request
|
||||
.addEntry()
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.GET)
|
||||
.setUrl("Patient?foobadparam=1");
|
||||
|
||||
Bundle response = mySystemDao.transaction(mySrd, request);
|
||||
assertEquals(2, response.getEntry().size());
|
||||
|
||||
assertEquals("201 Created", response.getEntry().get(0).getResponse().getStatus());
|
||||
assertThat(response.getEntry().get(0).getResponse().getLocation(), matchesPattern(".*Patient/[0-9]+.*"));
|
||||
assertEquals("400 Bad Request", response.getEntry().get(1).getResponse().getStatus());
|
||||
|
||||
OperationOutcome oo = (OperationOutcome) response.getEntry().get(1).getResponse().getOutcome();
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(oo));
|
||||
assertEquals(IssueSeverity.ERROR, oo.getIssue().get(0).getSeverity());
|
||||
assertThat(oo.getIssue().get(0).getDiagnostics(), containsString("Unknown search parameter"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionCreateWithDuplicateMatchUrl01() {
|
||||
String methodName = "testTransactionCreateWithDuplicateMatchUrl01";
|
||||
@ -914,7 +1050,7 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
||||
"Unable to process Transaction - Request would cause multiple resources to match URL: \"Patient?identifier=urn%3Asystem%7CtestTransactionCreateWithDuplicateMatchUrl02\". Does transaction request contain duplicates?");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testTransactionCreateWithInvalidMatchUrl() {
|
||||
String methodName = "testTransactionCreateWithInvalidMatchUrl";
|
||||
@ -949,6 +1085,7 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
||||
assertEquals("Failed to parse match URL[Patient?foo=bar] - Resource type Patient does not have a parameter with name: foo", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testTransactionCreateWithInvalidReferenceNumeric() {
|
||||
@ -1332,20 +1469,15 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
||||
|
||||
@Test
|
||||
public void testTransactionDoesNotLeavePlaceholderIds() throws Exception {
|
||||
newTxTemplate().execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
|
||||
String input;
|
||||
try {
|
||||
input = IOUtils.toString(getClass().getResourceAsStream("/cdr-bundle.json"), StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
fail(e.toString());
|
||||
return;
|
||||
}
|
||||
Bundle bundle = myFhirCtx.newJsonParser().parseResource(Bundle.class, input);
|
||||
mySystemDao.transaction(mySrd, bundle);
|
||||
}
|
||||
});
|
||||
String input;
|
||||
try {
|
||||
input = IOUtils.toString(getClass().getResourceAsStream("/cdr-bundle.json"), StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
fail(e.toString());
|
||||
return;
|
||||
}
|
||||
Bundle bundle = myFhirCtx.newJsonParser().parseResource(Bundle.class, input);
|
||||
mySystemDao.transaction(mySrd, bundle);
|
||||
|
||||
IBundleProvider history = mySystemDao.history(null, null, null);
|
||||
Bundle list = toBundle(history);
|
||||
@ -2161,16 +2293,16 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void testTransactionWithPlaceholderIdInMatchUrlPut() {
|
||||
public void testTransactionWithPlaceholderIdInMatchUrlPost() {
|
||||
|
||||
Bundle input = createInputTransactionWithPlaceholderIdInMatchUrl(HTTPVerb.PUT);
|
||||
Bundle input = createInputTransactionWithPlaceholderIdInMatchUrl(HTTPVerb.POST);
|
||||
Bundle output = mySystemDao.transaction(null, input);
|
||||
|
||||
assertEquals("201 Created", output.getEntry().get(0).getResponse().getStatus());
|
||||
assertEquals("201 Created", output.getEntry().get(1).getResponse().getStatus());
|
||||
assertEquals("201 Created", output.getEntry().get(2).getResponse().getStatus());
|
||||
|
||||
Bundle input2 = createInputTransactionWithPlaceholderIdInMatchUrl(HTTPVerb.PUT);
|
||||
Bundle input2 = createInputTransactionWithPlaceholderIdInMatchUrl(HTTPVerb.POST);
|
||||
Bundle output2 = mySystemDao.transaction(null, input2);
|
||||
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(output2));
|
||||
@ -2191,16 +2323,16 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
public void testTransactionWithPlaceholderIdInMatchUrlPost() {
|
||||
public void testTransactionWithPlaceholderIdInMatchUrlPut() {
|
||||
|
||||
Bundle input = createInputTransactionWithPlaceholderIdInMatchUrl(HTTPVerb.POST);
|
||||
Bundle input = createInputTransactionWithPlaceholderIdInMatchUrl(HTTPVerb.PUT);
|
||||
Bundle output = mySystemDao.transaction(null, input);
|
||||
|
||||
assertEquals("201 Created", output.getEntry().get(0).getResponse().getStatus());
|
||||
assertEquals("201 Created", output.getEntry().get(1).getResponse().getStatus());
|
||||
assertEquals("201 Created", output.getEntry().get(2).getResponse().getStatus());
|
||||
|
||||
Bundle input2 = createInputTransactionWithPlaceholderIdInMatchUrl(HTTPVerb.POST);
|
||||
Bundle input2 = createInputTransactionWithPlaceholderIdInMatchUrl(HTTPVerb.PUT);
|
||||
Bundle output2 = mySystemDao.transaction(null, input2);
|
||||
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(output2));
|
||||
@ -2247,6 +2379,7 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
||||
assertEquals("Joshua", patient.getNameFirstRep().getGivenAsSingleString());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testTransactionWithReferenceResource() {
|
||||
Bundle request = new Bundle();
|
||||
@ -2274,58 +2407,59 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
||||
assertEquals(1, found.size().intValue());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testTransactionWithReferenceToCreateIfNoneExist() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.setType(BundleType.TRANSACTION);
|
||||
|
||||
Medication med = new Medication();
|
||||
IdType medId = IdType.newRandomUuid();
|
||||
med.setId(medId);
|
||||
med.getCode().addCoding().setSystem("billscodes").setCode("theCode");
|
||||
bundle.addEntry().setResource(med).setFullUrl(medId.getValue()).getRequest().setMethod(HTTPVerb.POST).setIfNoneExist("Medication?code=billscodes|theCode");
|
||||
|
||||
MedicationRequest mo = new MedicationRequest();
|
||||
mo.setMedication(new Reference(medId));
|
||||
bundle.addEntry().setResource(mo).setFullUrl(mo.getIdElement().getValue()).getRequest().setMethod(HTTPVerb.POST);
|
||||
|
||||
ourLog.info("Request:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle));
|
||||
|
||||
Bundle outcome = mySystemDao.transaction(mySrd, bundle);
|
||||
ourLog.info("Response:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
|
||||
|
||||
IdType medId1 = new IdType(outcome.getEntry().get(0).getResponse().getLocation());
|
||||
IdType medOrderId1 = new IdType(outcome.getEntry().get(1).getResponse().getLocation());
|
||||
|
||||
/*
|
||||
* Again!
|
||||
*/
|
||||
|
||||
bundle = new Bundle();
|
||||
bundle.setType(BundleType.TRANSACTION);
|
||||
|
||||
med = new Medication();
|
||||
medId = IdType.newRandomUuid();
|
||||
med.getCode().addCoding().setSystem("billscodes").setCode("theCode");
|
||||
bundle.addEntry().setResource(med).setFullUrl(medId.getValue()).getRequest().setMethod(HTTPVerb.POST).setIfNoneExist("Medication?code=billscodes|theCode");
|
||||
|
||||
mo = new MedicationRequest();
|
||||
mo.setMedication(new Reference(medId));
|
||||
bundle.addEntry().setResource(mo).setFullUrl(mo.getIdElement().getValue()).getRequest().setMethod(HTTPVerb.POST);
|
||||
|
||||
outcome = mySystemDao.transaction(mySrd, bundle);
|
||||
|
||||
IdType medId2 = new IdType(outcome.getEntry().get(0).getResponse().getLocation());
|
||||
IdType medOrderId2 = new IdType(outcome.getEntry().get(1).getResponse().getLocation());
|
||||
|
||||
assertTrue(medId1.isIdPartValidLong());
|
||||
assertTrue(medId2.isIdPartValidLong());
|
||||
assertTrue(medOrderId1.isIdPartValidLong());
|
||||
assertTrue(medOrderId2.isIdPartValidLong());
|
||||
|
||||
assertEquals(medId1, medId2);
|
||||
assertNotEquals(medOrderId1, medOrderId2);
|
||||
}
|
||||
public void testTransactionWithReferenceToCreateIfNoneExist() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.setType(BundleType.TRANSACTION);
|
||||
|
||||
Medication med = new Medication();
|
||||
IdType medId = IdType.newRandomUuid();
|
||||
med.setId(medId);
|
||||
med.getCode().addCoding().setSystem("billscodes").setCode("theCode");
|
||||
bundle.addEntry().setResource(med).setFullUrl(medId.getValue()).getRequest().setMethod(HTTPVerb.POST).setIfNoneExist("Medication?code=billscodes|theCode");
|
||||
|
||||
MedicationRequest mo = new MedicationRequest();
|
||||
mo.setMedication(new Reference(medId));
|
||||
bundle.addEntry().setResource(mo).setFullUrl(mo.getIdElement().getValue()).getRequest().setMethod(HTTPVerb.POST);
|
||||
|
||||
ourLog.info("Request:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle));
|
||||
|
||||
Bundle outcome = mySystemDao.transaction(mySrd, bundle);
|
||||
ourLog.info("Response:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
|
||||
|
||||
IdType medId1 = new IdType(outcome.getEntry().get(0).getResponse().getLocation());
|
||||
IdType medOrderId1 = new IdType(outcome.getEntry().get(1).getResponse().getLocation());
|
||||
|
||||
/*
|
||||
* Again!
|
||||
*/
|
||||
|
||||
bundle = new Bundle();
|
||||
bundle.setType(BundleType.TRANSACTION);
|
||||
|
||||
med = new Medication();
|
||||
medId = IdType.newRandomUuid();
|
||||
med.getCode().addCoding().setSystem("billscodes").setCode("theCode");
|
||||
bundle.addEntry().setResource(med).setFullUrl(medId.getValue()).getRequest().setMethod(HTTPVerb.POST).setIfNoneExist("Medication?code=billscodes|theCode");
|
||||
|
||||
mo = new MedicationRequest();
|
||||
mo.setMedication(new Reference(medId));
|
||||
bundle.addEntry().setResource(mo).setFullUrl(mo.getIdElement().getValue()).getRequest().setMethod(HTTPVerb.POST);
|
||||
|
||||
outcome = mySystemDao.transaction(mySrd, bundle);
|
||||
|
||||
IdType medId2 = new IdType(outcome.getEntry().get(0).getResponse().getLocation());
|
||||
IdType medOrderId2 = new IdType(outcome.getEntry().get(1).getResponse().getLocation());
|
||||
|
||||
assertTrue(medId1.isIdPartValidLong());
|
||||
assertTrue(medId2.isIdPartValidLong());
|
||||
assertTrue(medOrderId1.isIdPartValidLong());
|
||||
assertTrue(medOrderId2.isIdPartValidLong());
|
||||
|
||||
assertEquals(medId1, medId2);
|
||||
assertNotEquals(medOrderId1, medOrderId2);
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
@ -2429,7 +2563,8 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
||||
//
|
||||
// }
|
||||
|
||||
@Test
|
||||
|
||||
@Test
|
||||
public void testTransactionWithReferenceUuid() {
|
||||
Bundle request = new Bundle();
|
||||
|
||||
|
@ -2,9 +2,16 @@ package ca.uhn.fhir.jpa.provider.dstu3;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
@ -1973,7 +1980,9 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
||||
.execute();
|
||||
|
||||
assertEquals(10, response.getEntry().size());
|
||||
assertEquals(null, response.getTotalElement().getValueAsString());
|
||||
if (response.getTotalElement().getValueAsString() != null) {
|
||||
assertEquals("21", response.getTotalElement().getValueAsString());
|
||||
}
|
||||
assertThat(response.getLink("next").getUrl(), not(emptyString()));
|
||||
|
||||
// Load page 2
|
||||
@ -1982,7 +1991,9 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
||||
response = ourClient.fetchResourceFromUrl(Bundle.class, nextUrl);
|
||||
|
||||
assertEquals(10, response.getEntry().size());
|
||||
assertEquals(null, response.getTotalElement().getValueAsString());
|
||||
if (response.getTotalElement().getValueAsString() != null) {
|
||||
assertEquals("21", response.getTotalElement().getValueAsString());
|
||||
}
|
||||
assertThat(response.getLink("next").getUrl(), not(emptyString()));
|
||||
|
||||
// Load page 3
|
||||
@ -1992,7 +2003,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
||||
response = ourClient.fetchResourceFromUrl(Bundle.class, nextUrl);
|
||||
|
||||
assertEquals(1, response.getEntry().size());
|
||||
assertEquals(21, response.getTotal());
|
||||
assertEquals("21", response.getTotalElement().getValueAsString());
|
||||
assertEquals(null, response.getLink("next"));
|
||||
|
||||
}
|
||||
@ -3187,6 +3198,31 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
||||
}
|
||||
}
|
||||
|
||||
@Test()
|
||||
public void testSearchNegativeNumbers() throws Exception {
|
||||
Observation o = new Observation();
|
||||
o.setValue(new Quantity().setValue(new BigDecimal("-10")));
|
||||
String oid1 = myObservationDao.create(o, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
Observation o2 = new Observation();
|
||||
o2.setValue(new Quantity().setValue(new BigDecimal("-20")));
|
||||
String oid2 = myObservationDao.create(o2, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
HttpGet get = new HttpGet(ourServerBase + "/Observation?value-quantity=gt-15");
|
||||
CloseableHttpResponse resp = ourHttpClient.execute(get);
|
||||
try {
|
||||
assertEquals(200, resp.getStatusLine().getStatusCode());
|
||||
Bundle bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, IOUtils.toString(resp.getEntity().getContent(), Constants.CHARSET_UTF8));
|
||||
|
||||
List<String> ids = toUnqualifiedVersionlessIdValues(bundle);
|
||||
assertThat(ids, contains(oid1));
|
||||
assertThat(ids, not(contains(oid2)));
|
||||
} finally {
|
||||
IOUtils.closeQuietly(resp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test(expected = InvalidRequestException.class)
|
||||
public void testSearchWithInvalidSort() throws Exception {
|
||||
Observation o = new Observation();
|
||||
|
@ -24,6 +24,7 @@ import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.*;
|
||||
import ca.uhn.fhir.jpa.dao.data.*;
|
||||
import ca.uhn.fhir.jpa.entity.*;
|
||||
import ca.uhn.fhir.jpa.util.BaseIterator;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
@ -139,9 +140,6 @@ public class SearchCoordinatorSvcImplTest {
|
||||
|
||||
}
|
||||
|
||||
private String newUuid() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
@Test
|
||||
public void testAsyncSearchLargeResultSetBigCountSameCoordinator() {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
@ -392,7 +390,7 @@ public class SearchCoordinatorSvcImplTest {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
public static class FailAfterNIterator<T> implements Iterator<T> {
|
||||
public static class FailAfterNIterator<T> extends BaseIterator<T> implements Iterator<T> {
|
||||
|
||||
private int myCount;
|
||||
private Iterator<T> myWrap;
|
||||
@ -419,7 +417,7 @@ public class SearchCoordinatorSvcImplTest {
|
||||
}
|
||||
|
||||
|
||||
public static class SlowIterator<T> implements Iterator<T> {
|
||||
public static class SlowIterator<T> extends BaseIterator<T> implements Iterator<T> {
|
||||
|
||||
private int myDelay;
|
||||
private Iterator<T> myWrap;
|
||||
|
@ -6,6 +6,7 @@ import static org.junit.Assert.fail;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
@ -15,6 +16,7 @@ import org.hl7.fhir.dstu3.model.Bundle.BundleType;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb;
|
||||
import org.junit.*;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import ca.uhn.fhir.jpa.provider.dstu3.BaseResourceProviderDstu3Test;
|
||||
@ -42,6 +44,37 @@ public class StressTestDstu3Test extends BaseResourceProviderDstu3Test {
|
||||
|
||||
ourRestServer.unregisterInterceptor(myRequestValidatingInterceptor);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMultithreadedSearch() throws Exception {
|
||||
Bundle input = new Bundle();
|
||||
input.setType(BundleType.TRANSACTION);
|
||||
for (int i = 0; i < 500; i++) {
|
||||
Patient p = new Patient();
|
||||
p.addIdentifier().setSystem("http://test").setValue("BAR");
|
||||
input.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.POST).setUrl("Patient");
|
||||
}
|
||||
ourClient.transaction().withBundle(input).execute();
|
||||
|
||||
|
||||
List<BaseTask> tasks = Lists.newArrayList();
|
||||
try {
|
||||
for (int threadIndex = 0; threadIndex < 10; threadIndex++) {
|
||||
SearchTask task = new SearchTask();
|
||||
tasks.add(task);
|
||||
task.start();
|
||||
}
|
||||
} finally {
|
||||
for (BaseTask next : tasks) {
|
||||
next.join();
|
||||
}
|
||||
}
|
||||
|
||||
validateNoErrors(tasks);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This test prevents a deadlock that was detected with a large number of
|
||||
@ -73,12 +106,12 @@ public class StressTestDstu3Test extends BaseResourceProviderDstu3Test {
|
||||
|
||||
List<BaseTask> tasks = Lists.newArrayList();
|
||||
try {
|
||||
for (int threadIndex = 0; threadIndex < 8; threadIndex++) {
|
||||
for (int threadIndex = 0; threadIndex < 5; threadIndex++) {
|
||||
SearchTask task = new SearchTask();
|
||||
tasks.add(task);
|
||||
task.start();
|
||||
}
|
||||
for (int threadIndex = 0; threadIndex < 8; threadIndex++) {
|
||||
for (int threadIndex = 0; threadIndex < 5; threadIndex++) {
|
||||
CreateTask task = new CreateTask();
|
||||
tasks.add(task);
|
||||
task.start();
|
||||
@ -89,6 +122,10 @@ public class StressTestDstu3Test extends BaseResourceProviderDstu3Test {
|
||||
}
|
||||
}
|
||||
|
||||
validateNoErrors(tasks);
|
||||
}
|
||||
|
||||
private void validateNoErrors(List<BaseTask> tasks) {
|
||||
int total = 0;
|
||||
for (BaseTask next : tasks) {
|
||||
if (next.getError() != null) {
|
||||
@ -127,16 +164,37 @@ public class StressTestDstu3Test extends BaseResourceProviderDstu3Test {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
CloseableHttpResponse get = null;
|
||||
for (int i = 0; i < 20; i++) {
|
||||
CloseableHttpResponse getResp = null;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
try {
|
||||
get = ourHttpClient.execute(new HttpGet(ourServerBase + "/Patient?identifier=http%3A%2F%2Ftest%7CBAR," + UUID.randomUUID().toString()));
|
||||
Bundle respBundle;
|
||||
|
||||
// Load search
|
||||
HttpGet get = new HttpGet(ourServerBase + "/Patient?identifier=http%3A%2F%2Ftest%7CBAR," + UUID.randomUUID().toString());
|
||||
get.addHeader(Constants.HEADER_CONTENT_TYPE, Constants.CT_FHIR_JSON_NEW);
|
||||
getResp = ourHttpClient.execute(get);
|
||||
try {
|
||||
assertEquals(200, get.getStatusLine().getStatusCode());
|
||||
assertEquals(200, getResp.getStatusLine().getStatusCode());
|
||||
String respBundleString = IOUtils.toString(getResp.getEntity().getContent(), Charsets.UTF_8);
|
||||
respBundle = myFhirCtx.newJsonParser().parseResource(Bundle.class, respBundleString);
|
||||
myTaskCount++;
|
||||
} finally {
|
||||
IOUtils.closeQuietly(get);
|
||||
IOUtils.closeQuietly(getResp);
|
||||
}
|
||||
|
||||
// Load page 2
|
||||
get = new HttpGet(respBundle.getLink("next").getUrl());
|
||||
get.addHeader(Constants.HEADER_CONTENT_TYPE, Constants.CT_FHIR_JSON_NEW);
|
||||
getResp = ourHttpClient.execute(get);
|
||||
try {
|
||||
assertEquals(200, getResp.getStatusLine().getStatusCode());
|
||||
String respBundleString = IOUtils.toString(getResp.getEntity().getContent(), Charsets.UTF_8);
|
||||
respBundle = myFhirCtx.newJsonParser().parseResource(Bundle.class, respBundleString);
|
||||
myTaskCount++;
|
||||
} finally {
|
||||
IOUtils.closeQuietly(getResp);
|
||||
}
|
||||
|
||||
} catch (Throwable e) {
|
||||
ourLog.error("Failure during search", e);
|
||||
myError = e;
|
||||
|
@ -1,19 +1,18 @@
|
||||
package ca.uhn.fhir.rest.param;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.dstu.composite.CodingDt;
|
||||
import ca.uhn.fhir.rest.method.QualifiedParamList;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TokenOrListParamTest {
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class TokenOrListParamDstu2Test {
|
||||
@Test
|
||||
public void testWhenParamListHasAnyMatchingCodingsForCodingList_doesCodingListMatch_shouldBeTrue() {
|
||||
TokenOrListParam params = new TokenOrListParam();
|
||||
@ -53,22 +52,6 @@ public class TokenOrListParamTest {
|
||||
assertFalse(params.doesCodingListMatch(codings));
|
||||
}
|
||||
|
||||
/**
|
||||
* See #192
|
||||
*/
|
||||
@Test
|
||||
public void testParseExcaped() {
|
||||
TokenOrListParam params = new TokenOrListParam();
|
||||
params.setValuesAsQueryTokens(ourCtx, null, QualifiedParamList.singleton("system|code-include-but-not-end-with-comma\\,suffix"));
|
||||
|
||||
assertEquals(1, params.getListAsCodings().size());
|
||||
assertEquals("system", params.getListAsCodings().get(0).getSystemElement().getValue());
|
||||
assertEquals("code-include-but-not-end-with-comma,suffix", params.getListAsCodings().get(0).getCodeElement().getValue());
|
||||
}
|
||||
|
||||
|
||||
private static FhirContext ourCtx = FhirContext.forDstu1();
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
@ -47,7 +47,8 @@ import org.hl7.fhir.exceptions.FHIRException;
|
||||
* A statement of relationships from one set of concepts to one or more other concepts - either code systems or data elements, or classes in class models.
|
||||
*/
|
||||
@ResourceDef(name="ConceptMap", profile="http://hl7.org/fhir/Profile/ConceptMap")
|
||||
@ChildOrder(names={"url", "identifier", "version", "name", "title", "status", "experimental", "date", "publisher", "contact", "description", "useContext", "jurisdiction", "purpose", "copyright", "source[x]", "target[x]", "group"})
|
||||
//@ChildOrder(names={"url", "identifier", "version", "name", "title", "status", "experimental", "date", "publisher", "contact", "description", "useContext", "jurisdiction", "purpose", "copyright", "source[x]", "target[x]", "group"})
|
||||
@ChildOrder(names={"url", "identifier", "version", "name", "title", "status", "experimental", "date", "publisher", "contact", "description", "useContext", "jurisdiction", "purpose", "copyright", "source", "target", "group"})
|
||||
public class ConceptMap extends MetadataResource {
|
||||
|
||||
public enum ConceptMapGroupUnmappedMode {
|
||||
|
@ -1,17 +1,10 @@
|
||||
package ca.uhn.fhir.parser;
|
||||
|
||||
import org.hl7.fhir.dstu3.model.DateTimeType;
|
||||
import org.hl7.fhir.dstu3.model.DomainResource;
|
||||
import org.hl7.fhir.dstu3.model.ResourceType;
|
||||
import org.hl7.fhir.dstu3.model.Type;
|
||||
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.instance.model.api.ICompositeType;
|
||||
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.model.api.IElement;
|
||||
import ca.uhn.fhir.model.api.annotation.Child;
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
import ca.uhn.fhir.model.api.annotation.*;
|
||||
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
|
||||
|
@ -31,6 +31,8 @@ import java.util.*;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.hamcrest.core.StringContains;
|
||||
import org.hl7.fhir.dstu3.hapi.validation.DefaultProfileValidationSupport;
|
||||
import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.dstu3.model.Address.AddressUse;
|
||||
import org.hl7.fhir.dstu3.model.Address.AddressUseEnumFactory;
|
||||
@ -42,6 +44,7 @@ import org.hl7.fhir.dstu3.model.Enumeration;
|
||||
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
|
||||
import org.hl7.fhir.dstu3.model.Identifier.IdentifierUse;
|
||||
import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||
import org.junit.*;
|
||||
@ -59,8 +62,7 @@ import ca.uhn.fhir.parser.XmlParserDstu3Test.TestPatientFor327;
|
||||
import ca.uhn.fhir.parser.json.JsonLikeValue.ScalarType;
|
||||
import ca.uhn.fhir.parser.json.JsonLikeValue.ValueType;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import ca.uhn.fhir.validation.FhirValidator;
|
||||
import ca.uhn.fhir.validation.ValidationResult;
|
||||
import ca.uhn.fhir.validation.*;
|
||||
import net.sf.json.*;
|
||||
|
||||
public class JsonParserDstu3Test {
|
||||
@ -71,6 +73,78 @@ public class JsonParserDstu3Test {
|
||||
public void after() {
|
||||
ourCtx.setNarrativeGenerator(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActivityDefinitionElementsOrder() throws Exception {
|
||||
final String origContent = "{\"resourceType\":\"ActivityDefinition\",\"id\":\"x1\",\"url\":\"http://testing.org\",\"status\":\"draft\",\"timingDateTime\":\"2011-02-03\"}";
|
||||
final IParser parser = ourCtx.newJsonParser();
|
||||
DefaultProfileValidationSupport validationSupport = new DefaultProfileValidationSupport();
|
||||
|
||||
// verify that InstanceValidator likes the format
|
||||
{
|
||||
IValidationContext<IBaseResource> validationCtx = ValidationContext.forText(ourCtx, origContent);
|
||||
new FhirInstanceValidator(validationSupport).validateResource(validationCtx);
|
||||
ValidationResult result = validationCtx.toResult();
|
||||
for (SingleValidationMessage msg : result.getMessages()) {
|
||||
ourLog.info("{}", msg);
|
||||
}
|
||||
Assert.assertEquals(0, result.getMessages().size());
|
||||
}
|
||||
|
||||
ActivityDefinition fhirObj = parser.parseResource(ActivityDefinition.class, origContent);
|
||||
String content = parser.encodeResourceToString(fhirObj);
|
||||
ourLog.info("Serialized form: {}", content);
|
||||
|
||||
// verify that InstanceValidator still likes the format
|
||||
{
|
||||
IValidationContext<IBaseResource> validationCtx = ValidationContext.forText(ourCtx, content);
|
||||
new FhirInstanceValidator(validationSupport).validateResource(validationCtx);
|
||||
ValidationResult result = validationCtx.toResult();
|
||||
for (SingleValidationMessage msg : result.getMessages()) {
|
||||
ourLog.info("{}", msg);
|
||||
}
|
||||
Assert.assertEquals(0, result.getMessages().size());
|
||||
}
|
||||
|
||||
// verify that the original and newly serialized match
|
||||
Assert.assertEquals(origContent, content);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConceptMapElementsOrder() throws Exception {
|
||||
final String origContent = "{\"resourceType\":\"ConceptMap\",\"id\":\"x1\",\"url\":\"http://testing.org\",\"status\":\"draft\",\"sourceUri\":\"http://y1\"}";
|
||||
final IParser parser = ourCtx.newJsonParser();
|
||||
DefaultProfileValidationSupport validationSupport = new DefaultProfileValidationSupport();
|
||||
|
||||
// verify that InstanceValidator likes the format
|
||||
{
|
||||
IValidationContext<IBaseResource> validationCtx = ValidationContext.forText(ourCtx, origContent);
|
||||
new FhirInstanceValidator(validationSupport).validateResource(validationCtx);
|
||||
ValidationResult result = validationCtx.toResult();
|
||||
for (SingleValidationMessage msg : result.getMessages()) {
|
||||
ourLog.info("{}", msg);
|
||||
}
|
||||
Assert.assertEquals(0, result.getMessages().size());
|
||||
}
|
||||
|
||||
ConceptMap fhirObj = parser.parseResource(ConceptMap.class, origContent);
|
||||
String content = parser.encodeResourceToString(fhirObj);
|
||||
ourLog.info("Serialized form: {}", content);
|
||||
|
||||
// verify that InstanceValidator still likes the format
|
||||
{
|
||||
IValidationContext<IBaseResource> validationCtx = ValidationContext.forText(ourCtx, content);
|
||||
new FhirInstanceValidator(validationSupport).validateResource(validationCtx);
|
||||
ValidationResult result = validationCtx.toResult();
|
||||
for (SingleValidationMessage msg : result.getMessages()) {
|
||||
ourLog.info("{}", msg);
|
||||
}
|
||||
Assert.assertEquals(0, result.getMessages().size());
|
||||
}
|
||||
|
||||
// verify that the original and newly serialized match
|
||||
Assert.assertEquals(origContent, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* See #563
|
||||
|
@ -34,6 +34,8 @@ import org.custommonkey.xmlunit.XMLUnit;
|
||||
import org.hamcrest.collection.IsEmptyCollection;
|
||||
import org.hamcrest.core.StringContains;
|
||||
import org.hamcrest.text.StringContainsInOrder;
|
||||
import org.hl7.fhir.dstu3.hapi.validation.DefaultProfileValidationSupport;
|
||||
import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.dstu3.model.Address.AddressUse;
|
||||
import org.hl7.fhir.dstu3.model.Address.AddressUseEnumFactory;
|
||||
@ -64,6 +66,10 @@ import ca.uhn.fhir.parser.IParserErrorHandler.IParseLocation;
|
||||
import ca.uhn.fhir.parser.PatientWithCustomCompositeExtension.FooParentExtension;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import ca.uhn.fhir.validation.IValidationContext;
|
||||
import ca.uhn.fhir.validation.SingleValidationMessage;
|
||||
import ca.uhn.fhir.validation.ValidationContext;
|
||||
import ca.uhn.fhir.validation.ValidationResult;
|
||||
|
||||
public class XmlParserDstu3Test {
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
@ -76,7 +82,7 @@ public class XmlParserDstu3Test {
|
||||
}
|
||||
ourCtx.setNarrativeGenerator(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See #544
|
||||
*/
|
||||
@ -104,7 +110,7 @@ public class XmlParserDstu3Test {
|
||||
assertNotNull(subject);
|
||||
assertEquals("FAMILY", subject.getNameFirstRep().getFamily());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBundleWithBinary() {
|
||||
|
||||
@ -135,6 +141,81 @@ public class XmlParserDstu3Test {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* See #683
|
||||
*/
|
||||
@Test
|
||||
public void testChildOrderWithChoiceType() throws Exception {
|
||||
final String origContent = "<ActivityDefinition xmlns=\"http://hl7.org/fhir\"><id value=\"x1\"/><url value=\"http://testing.org\"/><status value=\"draft\"/><timingDateTime value=\"2011-02-03\"/></ActivityDefinition>";
|
||||
final IParser parser = ourCtx.newXmlParser();
|
||||
DefaultProfileValidationSupport validationSupport = new DefaultProfileValidationSupport();
|
||||
|
||||
// verify that InstanceValidator likes the format
|
||||
{
|
||||
IValidationContext<IBaseResource> validationCtx = ValidationContext.forText(ourCtx, origContent);
|
||||
new FhirInstanceValidator(validationSupport).validateResource(validationCtx);
|
||||
ValidationResult result = validationCtx.toResult();
|
||||
for (SingleValidationMessage msg : result.getMessages()) {
|
||||
ourLog.info("{}", msg);
|
||||
}
|
||||
Assert.assertEquals(0, result.getMessages().size());
|
||||
}
|
||||
|
||||
ActivityDefinition fhirObj = parser.parseResource(ActivityDefinition.class, origContent);
|
||||
String content = parser.encodeResourceToString(fhirObj);
|
||||
ourLog.info("Serialized form: {}", content);
|
||||
|
||||
// verify that InstanceValidator still likes the format
|
||||
{
|
||||
IValidationContext<IBaseResource> validationCtx = ValidationContext.forText(ourCtx, content);
|
||||
new FhirInstanceValidator(validationSupport).validateResource(validationCtx);
|
||||
ValidationResult result = validationCtx.toResult();
|
||||
for (SingleValidationMessage msg : result.getMessages()) {
|
||||
ourLog.info("{}", msg);
|
||||
}
|
||||
Assert.assertEquals(0, result.getMessages().size());
|
||||
}
|
||||
|
||||
// verify that the original and newly serialized match
|
||||
Assert.assertEquals(origContent, content);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConceptMapElementsOrder() throws Exception {
|
||||
final String origContent = "<ConceptMap xmlns=\"http://hl7.org/fhir\"><id value=\"x1\"/><url value=\"http://testing.org\"/><status value=\"draft\"/><sourceUri value=\"http://url1\"/></ConceptMap>";
|
||||
final IParser parser = ourCtx.newXmlParser();
|
||||
DefaultProfileValidationSupport validationSupport = new DefaultProfileValidationSupport();
|
||||
|
||||
// verify that InstanceValidator likes the format
|
||||
{
|
||||
IValidationContext<IBaseResource> validationCtx = ValidationContext.forText(ourCtx, origContent);
|
||||
new FhirInstanceValidator(validationSupport).validateResource(validationCtx);
|
||||
ValidationResult result = validationCtx.toResult();
|
||||
for (SingleValidationMessage msg : result.getMessages()) {
|
||||
ourLog.info("{}", msg);
|
||||
}
|
||||
Assert.assertEquals(0, result.getMessages().size());
|
||||
}
|
||||
|
||||
ConceptMap fhirObj = parser.parseResource(ConceptMap.class, origContent);
|
||||
String content = parser.encodeResourceToString(fhirObj);
|
||||
ourLog.info("Serialized form: {}", content);
|
||||
|
||||
// verify that InstanceValidator still likes the format
|
||||
{
|
||||
IValidationContext<IBaseResource> validationCtx = ValidationContext.forText(ourCtx, content);
|
||||
new FhirInstanceValidator(validationSupport).validateResource(validationCtx);
|
||||
ValidationResult result = validationCtx.toResult();
|
||||
for (SingleValidationMessage msg : result.getMessages()) {
|
||||
ourLog.info("{}", msg);
|
||||
}
|
||||
Assert.assertEquals(0, result.getMessages().size());
|
||||
}
|
||||
|
||||
// verify that the original and newly serialized match
|
||||
Assert.assertEquals(origContent, content);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContainedResourceInExtensionUndeclared() {
|
||||
Patient p = new Patient();
|
||||
|
@ -5,10 +5,7 @@ import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
import java.util.*;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
@ -18,13 +15,15 @@ import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
|
||||
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.rest.method.QualifiedParamList;
|
||||
import ca.uhn.fhir.rest.api.QualifiedParamList;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class DateRangeParamTest {
|
||||
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
private static final SimpleDateFormat ourFmt;
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(DateRangeParamTest.class);
|
||||
|
||||
static {
|
||||
@ -35,54 +34,6 @@ public class DateRangeParamTest {
|
||||
return new DateRangeParam(new DateParam(theString));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRangeFromDates() {
|
||||
TimeZone tz = TimeZone.getDefault();
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("America/Toronto"));
|
||||
try {
|
||||
Date startDate = new InstantDt("2010-01-01T00:00:00.000Z").getValue();
|
||||
Date endDate = new InstantDt("2010-01-01T00:00:00.001Z").getValue();
|
||||
DateTimeDt startDateTime = new DateTimeDt(startDate, TemporalPrecisionEnum.MILLI);
|
||||
DateTimeDt endDateTime = new DateTimeDt(endDate, TemporalPrecisionEnum.MILLI);
|
||||
|
||||
DateRangeParam range = new DateRangeParam(startDateTime, endDateTime);
|
||||
assertEquals("2009-12-31T19:00:00.000-05:00", range.getValuesAsQueryTokens().get(0).getValueAsString());
|
||||
assertEquals("2009-12-31T19:00:00.001-05:00", range.getValuesAsQueryTokens().get(1).getValueAsString());
|
||||
|
||||
// Now try with arguments reversed (should still create same range)
|
||||
range = new DateRangeParam(endDateTime, startDateTime);
|
||||
assertEquals("2009-12-31T19:00:00.000-05:00", range.getValuesAsQueryTokens().get(0).getValueAsString());
|
||||
assertEquals("2009-12-31T19:00:00.001-05:00", range.getValuesAsQueryTokens().get(1).getValueAsString());
|
||||
|
||||
} finally {
|
||||
TimeZone.setDefault(tz);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRange() {
|
||||
InstantDt start = new InstantDt("2015-09-23T07:43:34.811-04:00");
|
||||
InstantDt end = new InstantDt("2015-09-23T07:43:34.899-04:00");
|
||||
DateParam lowerBound = new DateParam(QuantityCompararatorEnum.GREATERTHAN, start.getValue());
|
||||
DateParam upperBound = new DateParam(QuantityCompararatorEnum.LESSTHAN, end.getValue());
|
||||
assertEquals(QuantityCompararatorEnum.GREATERTHAN, lowerBound.getComparator());
|
||||
assertEquals(QuantityCompararatorEnum.LESSTHAN, upperBound.getComparator());
|
||||
|
||||
/*
|
||||
* When DateParam (which extends DateTimeDt) gets passed in, make sure we preserve the comparators..
|
||||
*/
|
||||
DateRangeParam param = new DateRangeParam(lowerBound, upperBound);
|
||||
ourLog.info(param.toString());
|
||||
assertEquals(QuantityCompararatorEnum.GREATERTHAN, param.getLowerBound().getComparator());
|
||||
assertEquals(QuantityCompararatorEnum.LESSTHAN, param.getUpperBound().getComparator());
|
||||
|
||||
param = new DateRangeParam(new DateTimeDt(lowerBound.getValue()), new DateTimeDt(upperBound.getValue()));
|
||||
ourLog.info(param.toString());
|
||||
assertEquals(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, param.getLowerBound().getComparator());
|
||||
assertEquals(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS, param.getUpperBound().getComparator());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddAnd() {
|
||||
assertEquals(1, new DateAndListParam().addAnd(new DateOrListParam()).getValuesAsQueryTokens().size());
|
||||
@ -159,6 +110,54 @@ public class DateRangeParamTest {
|
||||
assertNotNull(new StringOrListParam().newInstance());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRange() {
|
||||
InstantDt start = new InstantDt("2015-09-23T07:43:34.811-04:00");
|
||||
InstantDt end = new InstantDt("2015-09-23T07:43:34.899-04:00");
|
||||
DateParam lowerBound = new DateParam(QuantityCompararatorEnum.GREATERTHAN, start.getValue());
|
||||
DateParam upperBound = new DateParam(QuantityCompararatorEnum.LESSTHAN, end.getValue());
|
||||
assertEquals(QuantityCompararatorEnum.GREATERTHAN, lowerBound.getComparator());
|
||||
assertEquals(QuantityCompararatorEnum.LESSTHAN, upperBound.getComparator());
|
||||
|
||||
/*
|
||||
* When DateParam (which extends DateTimeDt) gets passed in, make sure we preserve the comparators..
|
||||
*/
|
||||
DateRangeParam param = new DateRangeParam(lowerBound, upperBound);
|
||||
ourLog.info(param.toString());
|
||||
assertEquals(QuantityCompararatorEnum.GREATERTHAN, param.getLowerBound().getComparator());
|
||||
assertEquals(QuantityCompararatorEnum.LESSTHAN, param.getUpperBound().getComparator());
|
||||
|
||||
param = new DateRangeParam(new DateTimeDt(lowerBound.getValue()), new DateTimeDt(upperBound.getValue()));
|
||||
ourLog.info(param.toString());
|
||||
assertEquals(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, param.getLowerBound().getComparator());
|
||||
assertEquals(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS, param.getUpperBound().getComparator());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRangeFromDates() {
|
||||
TimeZone tz = TimeZone.getDefault();
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("America/Toronto"));
|
||||
try {
|
||||
Date startDate = new InstantDt("2010-01-01T00:00:00.000Z").getValue();
|
||||
Date endDate = new InstantDt("2010-01-01T00:00:00.001Z").getValue();
|
||||
DateTimeDt startDateTime = new DateTimeDt(startDate, TemporalPrecisionEnum.MILLI);
|
||||
DateTimeDt endDateTime = new DateTimeDt(endDate, TemporalPrecisionEnum.MILLI);
|
||||
|
||||
DateRangeParam range = new DateRangeParam(startDateTime, endDateTime);
|
||||
assertEquals("2009-12-31T19:00:00.000-05:00", range.getValuesAsQueryTokens().get(0).getValueAsString());
|
||||
assertEquals("2009-12-31T19:00:00.001-05:00", range.getValuesAsQueryTokens().get(1).getValueAsString());
|
||||
|
||||
// Now try with arguments reversed (should still create same range)
|
||||
range = new DateRangeParam(endDateTime, startDateTime);
|
||||
assertEquals("2009-12-31T19:00:00.000-05:00", range.getValuesAsQueryTokens().get(0).getValueAsString());
|
||||
assertEquals("2009-12-31T19:00:00.001-05:00", range.getValuesAsQueryTokens().get(1).getValueAsString());
|
||||
|
||||
} finally {
|
||||
TimeZone.setDefault(tz);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSecond() throws Exception {
|
||||
assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011-01-01T00:00:00", "<2011-01-01T01:00:00").getLowerBoundAsInstant());
|
||||
@ -177,6 +176,11 @@ public class DateRangeParamTest {
|
||||
assertEquals(parseM1("2014-01-01 00:00:00.0000"), create(">2011", "<=2013").getUpperBoundAsInstant());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
private static DateRangeParam create(String theLower, String theUpper) throws InvalidRequestException {
|
||||
DateRangeParam p = new DateRangeParam();
|
||||
List<QualifiedParamList> tokens = new ArrayList<QualifiedParamList>();
|
||||
@ -188,8 +192,6 @@ public class DateRangeParamTest {
|
||||
return p;
|
||||
}
|
||||
|
||||
private static FhirContext ourCtx = FhirContext.forDstu1();
|
||||
|
||||
public static Date parse(String theString) throws ParseException {
|
||||
return ourFmt.parse(theString);
|
||||
}
|
||||
@ -198,9 +200,4 @@ public class DateRangeParamTest {
|
||||
return new Date(ourFmt.parse(theString).getTime() - 1L);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package ca.uhn.fhir.rest.param;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class NumberParamTest {
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
|
||||
@Test
|
||||
public void testFull() {
|
||||
NumberParam p = new NumberParam();
|
||||
p.setValueAsQueryToken(ourCtx, null, null, "<5.4");
|
||||
assertEquals(ParamPrefixEnum.LESSTHAN, p.getPrefix());
|
||||
assertEquals("5.4", p.getValue().toPlainString());
|
||||
assertEquals("lt5.4", p.getValueAsQueryToken(ourCtx));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApproximateLegacy() {
|
||||
NumberParam p = new NumberParam();
|
||||
p.setValueAsQueryToken(ourCtx, null, null, "~5.4");
|
||||
assertEquals(null,p.getComparator());
|
||||
assertEquals(ParamPrefixEnum.APPROXIMATE, p.getPrefix());
|
||||
assertEquals("5.4", p.getValue().toPlainString());
|
||||
assertEquals("ap5.4", p.getValueAsQueryToken(ourCtx));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApproximate() {
|
||||
NumberParam p = new NumberParam();
|
||||
p.setValueAsQueryToken(ourCtx, null, null, "ap5.4");
|
||||
assertEquals(null,p.getComparator());
|
||||
assertEquals(ParamPrefixEnum.APPROXIMATE, p.getPrefix());
|
||||
assertEquals("5.4", p.getValue().toPlainString());
|
||||
assertEquals("ap5.4", p.getValueAsQueryToken(ourCtx));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoQualifier() {
|
||||
NumberParam p = new NumberParam();
|
||||
p.setValueAsQueryToken(ourCtx, null, null, "5.4");
|
||||
assertEquals(null, p.getComparator());
|
||||
assertEquals(null, p.getPrefix());
|
||||
assertEquals("5.4", p.getValue().toPlainString());
|
||||
assertEquals("5.4", p.getValueAsQueryToken(ourCtx));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See #696
|
||||
*/
|
||||
@Test
|
||||
public void testNegativeNumber() {
|
||||
NumberParam p = new NumberParam();
|
||||
p.setValueAsQueryToken(ourCtx, null, null, "-5.4");
|
||||
assertEquals(null, p.getComparator());
|
||||
assertEquals(null, p.getPrefix());
|
||||
assertEquals("-5.4", p.getValue().toPlainString());
|
||||
assertEquals(new BigDecimal("-5.4"), p.getValue());
|
||||
assertEquals("-5.4", p.getValueAsQueryToken(ourCtx));
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
@ -2,6 +2,8 @@ package ca.uhn.fhir.rest.param;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
@ -10,37 +12,52 @@ import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class QuantityParamTest {
|
||||
private static FhirContext ourCtx = FhirContext.forDstu1();
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
|
||||
@Test
|
||||
public void testFull() {
|
||||
QuantityParam p = new QuantityParam();
|
||||
p.setValueAsQueryToken(ourCtx, null, null, "<5.4|http://unitsofmeasure.org|mg");
|
||||
assertEquals(QuantityCompararatorEnum.LESSTHAN,p.getComparator());
|
||||
assertEquals(ParamPrefixEnum.LESSTHAN, p.getPrefix());
|
||||
assertEquals("5.4", p.getValue().toPlainString());
|
||||
assertEquals("http://unitsofmeasure.org", p.getSystem());
|
||||
assertEquals("mg", p.getUnits());
|
||||
assertEquals("<5.4|http://unitsofmeasure.org|mg", p.getValueAsQueryToken(ourCtx));
|
||||
assertEquals("lt5.4|http://unitsofmeasure.org|mg", p.getValueAsQueryToken(ourCtx));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApproximateLegacy() {
|
||||
QuantityParam p = new QuantityParam();
|
||||
p.setValueAsQueryToken(ourCtx, null, null, "~5.4|http://unitsofmeasure.org|mg");
|
||||
assertEquals(null,p.getComparator());
|
||||
assertEquals(ParamPrefixEnum.APPROXIMATE, p.getPrefix());
|
||||
assertEquals(true, p.isApproximate());
|
||||
assertEquals("5.4", p.getValue().toPlainString());
|
||||
assertEquals("http://unitsofmeasure.org", p.getSystem());
|
||||
assertEquals("mg", p.getUnits());
|
||||
assertEquals("ap5.4|http://unitsofmeasure.org|mg", p.getValueAsQueryToken(ourCtx));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApproximate() {
|
||||
QuantityParam p = new QuantityParam();
|
||||
p.setValueAsQueryToken(ourCtx, null, null, "~5.4|http://unitsofmeasure.org|mg");
|
||||
p.setValueAsQueryToken(ourCtx, null, null, "ap5.4|http://unitsofmeasure.org|mg");
|
||||
assertEquals(null,p.getComparator());
|
||||
assertEquals(ParamPrefixEnum.APPROXIMATE, p.getPrefix());
|
||||
assertEquals(true, p.isApproximate());
|
||||
assertEquals("5.4", p.getValue().toPlainString());
|
||||
assertEquals("http://unitsofmeasure.org", p.getSystem());
|
||||
assertEquals("mg", p.getUnits());
|
||||
assertEquals("~5.4|http://unitsofmeasure.org|mg", p.getValueAsQueryToken(ourCtx));
|
||||
assertEquals("ap5.4|http://unitsofmeasure.org|mg", p.getValueAsQueryToken(ourCtx));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNoQualifier() {
|
||||
QuantityParam p = new QuantityParam();
|
||||
p.setValueAsQueryToken(ourCtx, null, null, "5.4|http://unitsofmeasure.org|mg");
|
||||
assertEquals(null, p.getComparator());
|
||||
assertEquals(null, p.getPrefix());
|
||||
assertEquals("5.4", p.getValue().toPlainString());
|
||||
assertEquals("http://unitsofmeasure.org", p.getSystem());
|
||||
assertEquals("mg", p.getUnits());
|
||||
@ -53,6 +70,7 @@ public class QuantityParamTest {
|
||||
QuantityParam p = new QuantityParam();
|
||||
p.setValueAsQueryToken(ourCtx, null, null, "5.4");
|
||||
assertEquals(null, p.getComparator());
|
||||
assertEquals(null, p.getPrefix());
|
||||
assertEquals("5.4", p.getValue().toPlainString());
|
||||
assertEquals(null, p.getSystem());
|
||||
assertEquals(null, p.getUnits());
|
||||
@ -84,6 +102,54 @@ public class QuantityParamTest {
|
||||
assertEquals("mg", param.getUnits());
|
||||
}
|
||||
|
||||
/**
|
||||
* See #696
|
||||
*/
|
||||
@Test
|
||||
public void testNegativeQuantityWithUnits() {
|
||||
QuantityParam p = new QuantityParam();
|
||||
p.setValueAsQueryToken(ourCtx, null, null, "-5.4|http://unitsofmeasure.org|mg");
|
||||
assertEquals(null, p.getComparator());
|
||||
assertEquals(null, p.getPrefix());
|
||||
assertEquals("-5.4", p.getValue().toPlainString());
|
||||
assertEquals(new BigDecimal("-5.4"), p.getValue());
|
||||
assertEquals("http://unitsofmeasure.org", p.getSystem());
|
||||
assertEquals("mg", p.getUnits());
|
||||
assertEquals("-5.4|http://unitsofmeasure.org|mg", p.getValueAsQueryToken(ourCtx));
|
||||
}
|
||||
|
||||
/**
|
||||
* See #696
|
||||
*/
|
||||
@Test
|
||||
public void testNegativeQuantityWithoutUnits() {
|
||||
QuantityParam p = new QuantityParam();
|
||||
p.setValueAsQueryToken(ourCtx, null, null, "-5.4");
|
||||
assertEquals(null, p.getComparator());
|
||||
assertEquals(null, p.getPrefix());
|
||||
assertEquals("-5.4", p.getValue().toPlainString());
|
||||
assertEquals(new BigDecimal("-5.4"), p.getValue());
|
||||
assertEquals(null, p.getSystem());
|
||||
assertEquals(null, p.getUnits());
|
||||
assertEquals("-5.4||", p.getValueAsQueryToken(ourCtx));
|
||||
}
|
||||
|
||||
/**
|
||||
* See #696
|
||||
*/
|
||||
@Test
|
||||
public void testNegativeQuantityWithoutUnitsWithComparator() {
|
||||
QuantityParam p = new QuantityParam();
|
||||
p.setValueAsQueryToken(ourCtx, null, null, "gt-5.4");
|
||||
assertEquals(QuantityCompararatorEnum.GREATERTHAN, p.getComparator());
|
||||
assertEquals(ParamPrefixEnum.GREATERTHAN, p.getPrefix());
|
||||
assertEquals("-5.4", p.getValue().toPlainString());
|
||||
assertEquals(new BigDecimal("-5.4"), p.getValue());
|
||||
assertEquals(null, p.getSystem());
|
||||
assertEquals(null, p.getUnits());
|
||||
assertEquals("gt-5.4||", p.getValueAsQueryToken(ourCtx));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
@ -10,15 +10,7 @@ import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class ReferenceParamTest {
|
||||
|
||||
@Test
|
||||
public void testWithResourceTypeAsQualifier() {
|
||||
|
||||
ReferenceParam rp = new ReferenceParam();
|
||||
rp.setValueAsQueryToken(ourCtx, null, ":Location", "123");
|
||||
assertEquals("Location", rp.getResourceType());
|
||||
assertEquals("123", rp.getIdPart());
|
||||
|
||||
}
|
||||
private FhirContext ourCtx = FhirContext.forDstu3();
|
||||
|
||||
@Test
|
||||
public void testWithResourceType() {
|
||||
@ -30,7 +22,15 @@ public class ReferenceParamTest {
|
||||
|
||||
}
|
||||
|
||||
private FhirContext ourCtx = FhirContext.forDstu1();
|
||||
@Test
|
||||
public void testWithResourceTypeAsQualifier() {
|
||||
|
||||
ReferenceParam rp = new ReferenceParam();
|
||||
rp.setValueAsQueryToken(ourCtx, null, ":Location", "123");
|
||||
assertEquals("Location", rp.getResourceType());
|
||||
assertEquals("123", rp.getIdPart());
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
@ -0,0 +1,34 @@
|
||||
package ca.uhn.fhir.rest.param;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.api.QualifiedParamList;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class TokenOrListParamDstu3Test {
|
||||
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
|
||||
/**
|
||||
* See #192
|
||||
*/
|
||||
@Test
|
||||
public void testParseExcaped() {
|
||||
TokenOrListParam params = new TokenOrListParam();
|
||||
params.setValuesAsQueryTokens(ourCtx, null, QualifiedParamList.singleton("system|code-include-but-not-end-with-comma\\,suffix"));
|
||||
|
||||
assertEquals(1, params.getListAsCodings().size());
|
||||
assertEquals("system", params.getListAsCodings().get(0).getSystemElement().getValue());
|
||||
assertEquals("code-include-but-not-end-with-comma,suffix", params.getListAsCodings().get(0).getCodeElement().getValue());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package org.hl7.fhir.r4.hapi.validation;
|
||||
package org.hl7.fhir.r4.hapi.ctx;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
@ -68,9 +68,9 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
||||
codeSystems = new HashMap<String, CodeSystem>();
|
||||
valueSets = new HashMap<String, ValueSet>();
|
||||
|
||||
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/instance/model/dstu3/valueset/valuesets.xml");
|
||||
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/instance/model/dstu3/valueset/v2-tables.xml");
|
||||
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/instance/model/dstu3/valueset/v3-codesystems.xml");
|
||||
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/r4/model/valueset/valuesets.xml");
|
||||
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/r4/model/valueset/v2-tables.xml");
|
||||
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/r4/model/valueset/v3-codesystems.xml");
|
||||
|
||||
myCodeSystems = codeSystems;
|
||||
myValueSets = valueSets;
|
||||
@ -184,9 +184,9 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
||||
if (structureDefinitions == null) {
|
||||
structureDefinitions = new HashMap<String, StructureDefinition>();
|
||||
|
||||
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/instance/model/dstu3/profile/profiles-resources.xml");
|
||||
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/instance/model/dstu3/profile/profiles-types.xml");
|
||||
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/instance/model/dstu3/profile/profiles-others.xml");
|
||||
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/r4/model/profile/profiles-resources.xml");
|
||||
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/r4/model/profile/profiles-types.xml");
|
||||
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/r4/model/profile/profiles-others.xml");
|
||||
|
||||
myStructureDefinitions = structureDefinitions;
|
||||
}
|
@ -28,7 +28,6 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
import org.hl7.fhir.r4.hapi.fluentpath.FluentPathR4;
|
||||
import org.hl7.fhir.r4.hapi.rest.server.R4BundleFactory;
|
||||
import org.hl7.fhir.r4.hapi.validation.DefaultProfileValidationSupport;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
|
||||
import ca.uhn.fhir.context.*;
|
||||
@ -41,89 +40,90 @@ import ca.uhn.fhir.util.ReflectionUtil;
|
||||
|
||||
public class FhirR4 implements IFhirVersion {
|
||||
|
||||
private String myId;
|
||||
private String myId;
|
||||
|
||||
@Override
|
||||
public IFluentPath createFluentPathExecutor(FhirContext theFhirContext) {
|
||||
return new FluentPathR4(theFhirContext);
|
||||
}
|
||||
@Override
|
||||
public IFluentPath createFluentPathExecutor(FhirContext theFhirContext) {
|
||||
return new FluentPathR4(theFhirContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IContextValidationSupport<?, ?, ?, ?, ?, ?> createValidationSupport() {
|
||||
return new DefaultProfileValidationSupport();
|
||||
}
|
||||
@Override
|
||||
public IContextValidationSupport<?, ?, ?, ?, ?, ?> createValidationSupport() {
|
||||
return ReflectionUtil.newInstanceOfFhirProfileValidationSupport("org.hl7.fhir.r4.hapi.validation.DefaultProfileValidationSupport");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseResource generateProfile(RuntimeResourceDefinition theRuntimeResourceDefinition, String theServerBase) {
|
||||
StructureDefinition retVal = new StructureDefinition();
|
||||
@Override
|
||||
public IBaseResource generateProfile(RuntimeResourceDefinition theRuntimeResourceDefinition, String theServerBase) {
|
||||
StructureDefinition retVal = new StructureDefinition();
|
||||
|
||||
RuntimeResourceDefinition def = theRuntimeResourceDefinition;
|
||||
RuntimeResourceDefinition def = theRuntimeResourceDefinition;
|
||||
|
||||
myId = def.getId();
|
||||
if (StringUtils.isBlank(myId)) {
|
||||
myId = theRuntimeResourceDefinition.getName().toLowerCase();
|
||||
}
|
||||
myId = def.getId();
|
||||
if (StringUtils.isBlank(myId)) {
|
||||
myId = theRuntimeResourceDefinition.getName().toLowerCase();
|
||||
}
|
||||
|
||||
retVal.setId(new IdDt(myId));
|
||||
return retVal;
|
||||
}
|
||||
retVal.setId(new IdDt(myId));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public Class<List> getContainedType() {
|
||||
return List.class;
|
||||
}
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public Class<List> getContainedType() {
|
||||
return List.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getFhirVersionPropertiesFile() {
|
||||
InputStream str = FhirR4.class.getResourceAsStream("/org/hl7/fhir/r4/model/fhirversion.properties");
|
||||
if (str == null) {
|
||||
str = FhirR4.class.getResourceAsStream("/org/hl7/fhir/r4/model/fhirversion.properties");
|
||||
}
|
||||
if (str == null) {
|
||||
throw new ConfigurationException("Can not find model property file on classpath: " + "/ca/uhn/fhir/model/r4/fhirversion.properties");
|
||||
}
|
||||
return str;
|
||||
}
|
||||
@Override
|
||||
public InputStream getFhirVersionPropertiesFile() {
|
||||
String path = "org/hl7/fhir/r4/model/fhirversion.properties";
|
||||
InputStream str = FhirR4.class.getResourceAsStream("/" + path);
|
||||
if (str == null) {
|
||||
str = FhirR4.class.getResourceAsStream(path);
|
||||
}
|
||||
if (str == null) {
|
||||
throw new ConfigurationException("Can not find model property file on classpath: " + path);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPrimitiveType<Date> getLastUpdated(IBaseResource theResource) {
|
||||
return ((Resource) theResource).getMeta().getLastUpdatedElement();
|
||||
}
|
||||
@Override
|
||||
public IPrimitiveType<Date> getLastUpdated(IBaseResource theResource) {
|
||||
return ((Resource) theResource).getMeta().getLastUpdatedElement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPathToSchemaDefinitions() {
|
||||
return "/org/hl7/fhir/instance/model/dstu3/schema";
|
||||
}
|
||||
@Override
|
||||
public String getPathToSchemaDefinitions() {
|
||||
return "/org/hl7/fhir/r4/model/schema";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends IBaseReference> getResourceReferenceType() {
|
||||
return Reference.class;
|
||||
}
|
||||
@Override
|
||||
public Class<? extends IBaseReference> getResourceReferenceType() {
|
||||
return Reference.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getServerVersion() {
|
||||
return ReflectionUtil.newInstanceOfFhirServerType("org.hl7.fhir.dstu3.hapi.ctx.FhirServerDstu3");
|
||||
}
|
||||
@Override
|
||||
public Object getServerVersion() {
|
||||
return ReflectionUtil.newInstanceOfFhirServerType("org.hl7.fhir.r4.hapi.ctx.FhirServerR4");
|
||||
}
|
||||
|
||||
@Override
|
||||
public FhirVersionEnum getVersion() {
|
||||
return FhirVersionEnum.R4;
|
||||
}
|
||||
@Override
|
||||
public FhirVersionEnum getVersion() {
|
||||
return FhirVersionEnum.R4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IVersionSpecificBundleFactory newBundleFactory(FhirContext theContext) {
|
||||
return new R4BundleFactory(theContext);
|
||||
}
|
||||
@Override
|
||||
public IVersionSpecificBundleFactory newBundleFactory(FhirContext theContext) {
|
||||
return new R4BundleFactory(theContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseCoding newCodingDt() {
|
||||
return new Coding();
|
||||
}
|
||||
@Override
|
||||
public IBaseCoding newCodingDt() {
|
||||
return new Coding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIdType newIdType() {
|
||||
return new IdType();
|
||||
}
|
||||
@Override
|
||||
public IIdType newIdType() {
|
||||
return new IdType();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,19 +1,17 @@
|
||||
package org.hl7.fhir.r4.hapi.validation;
|
||||
package org.hl7.fhir.r4.hapi.ctx;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
||||
import org.hl7.fhir.r4.context.IWorkerContext;
|
||||
import org.hl7.fhir.r4.formats.IParser;
|
||||
import org.hl7.fhir.r4.formats.ParserType;
|
||||
import org.hl7.fhir.r4.hapi.validation.IValidationSupport.CodeValidationResult;
|
||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport.CodeValidationResult;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionBindingComponent;
|
@ -1,4 +1,4 @@
|
||||
package org.hl7.fhir.r4.hapi.validation;
|
||||
package org.hl7.fhir.r4.hapi.ctx;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.hl7.fhir.r4.hapi.validation;
|
||||
package org.hl7.fhir.r4.hapi.ctx;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.hl7.fhir.r4.hapi.validation;
|
||||
package org.hl7.fhir.r4.hapi.ctx;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
@ -4,8 +4,8 @@ import java.util.List;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.r4.hapi.validation.HapiWorkerContext;
|
||||
import org.hl7.fhir.r4.hapi.validation.IValidationSupport;
|
||||
import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext;
|
||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r4.model.Base;
|
||||
import org.hl7.fhir.r4.utils.FHIRPathEngine;
|
||||
|
||||
|
@ -1,40 +0,0 @@
|
||||
package org.hl7.fhir.r4.hapi.validation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||
import org.hl7.fhir.r4.utils.FHIRPathEngine.IEvaluationContext;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator.BestPracticeWarningLevel;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator.IdStatus;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
public class InstanceValidator {
|
||||
|
||||
public InstanceValidator(HapiWorkerContext theWorkerContext, IEvaluationContext theEvaluationCtx) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
public void setBestPracticeWarningLevel(BestPracticeWarningLevel theBestPracticeWarningLevel) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
public void setAnyExtensionsAllowed(boolean theAnyExtensionsAllowed) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
public void setResourceIdRule(IdStatus theOptional) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
public void validate(Object theObject, List<ValidationMessage> theMessages, Document theDocument, StructureDefinition theProfile) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
public void validate(Object theObject, List<ValidationMessage> theMessages, JsonObject theJson, StructureDefinition theProfile) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
}
|
@ -167,7 +167,6 @@ import org.hl7.fhir.utilities.xml.XmlGenerator;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import com.github.rjeschke.txtmark.Processor;
|
||||
import com.sun.webkit.BackForwardList;
|
||||
|
||||
public class NarrativeGenerator implements INarrativeGenerator {
|
||||
|
||||
|
@ -0,0 +1,92 @@
|
||||
package ca.uhn.fhir.parser;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.ICompositeType;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.model.api.annotation.*;
|
||||
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
|
||||
/**
|
||||
* This is an example of a custom resource that also uses a custom
|
||||
* datatype.
|
||||
*
|
||||
* See #364
|
||||
*/
|
||||
@ResourceDef(name = "CustomResource", profile = "http://hl7.org/fhir/profiles/custom-resource", id = "custom-resource")
|
||||
public class CustomResource364R4 extends DomainResource {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Child(name = "baseValue", min = 1, max = Child.MAX_UNLIMITED, type= {})
|
||||
private Type baseValues;
|
||||
|
||||
public Type getBaseValues() {
|
||||
return baseValues;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FhirVersionEnum getStructureFhirVersionEnum() {
|
||||
return FhirVersionEnum.R4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return ElementUtil.isEmpty(baseValues);
|
||||
}
|
||||
|
||||
public void setBaseValues(Type theValue) {
|
||||
this.baseValues = theValue;
|
||||
}
|
||||
|
||||
@DatatypeDef(name="CustomDate")
|
||||
public static class CustomResource364CustomDate extends Type implements ICompositeType {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Child(name = "date", order = 0, min = 1, max = 1, type = { DateTimeDt.class })
|
||||
private DateTimeType date;
|
||||
|
||||
|
||||
public DateTimeType getDate() {
|
||||
if (date == null)
|
||||
date = new DateTimeType();
|
||||
return date;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return ElementUtil.isEmpty(date);
|
||||
}
|
||||
|
||||
public CustomResource364CustomDate setDate(DateTimeType theValue) {
|
||||
date = theValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CustomResource364CustomDate typedCopy() {
|
||||
CustomResource364CustomDate retVal = new CustomResource364CustomDate();
|
||||
super.copyValues(retVal);
|
||||
retVal.date = date;
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomResource364R4 copy() {
|
||||
CustomResource364R4 retVal = new CustomResource364R4();
|
||||
super.copyValues(retVal);
|
||||
retVal.baseValues = baseValues;
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ResourceType getResourceType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,647 @@
|
||||
package ca.uhn.fhir.parser;
|
||||
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.junit.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.api.AddProfileTagEnum;
|
||||
import ca.uhn.fhir.model.api.annotation.*;
|
||||
import ca.uhn.fhir.model.api.annotation.Extension;
|
||||
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.parser.CustomResource364R4.CustomResource364CustomDate;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class CustomTypeR4Test {
|
||||
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CustomTypeR4Test.class);
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourCtx.setAddProfileTagWhenEncoding(AddProfileTagEnum.ONLY_FOR_CUSTOM);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ResourceDef
|
||||
public static class PatientWithExtensionWithTwoTypes extends Patient {
|
||||
@Child(name = "foo", type = { DateTimeType.class, Period.class }, min = 0, max = 1)
|
||||
@Extension(url = "http://example.com/extension#foo", definedLocally = true, isModifier = false)
|
||||
@Description(shortDefinition = "Some description")
|
||||
private Type foo;
|
||||
|
||||
public Type getFoo() {
|
||||
return foo;
|
||||
}
|
||||
|
||||
public void setFoo(Type theFoo) {
|
||||
foo = theFoo;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtensionWithTwoTypes() {
|
||||
PatientWithExtensionWithTwoTypes pt = new PatientWithExtensionWithTwoTypes();
|
||||
pt.setFoo(new DateTimeType("2011-01-01T00:00:00Z"));
|
||||
|
||||
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(pt);
|
||||
ourLog.info(encoded);
|
||||
|
||||
pt = ourCtx.newXmlParser().parseResource(PatientWithExtensionWithTwoTypes.class, encoded);
|
||||
assertEquals("2011-01-01T00:00:00Z", ((DateTimeType)pt.getFoo()).getValueAsString());
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ResourceDef
|
||||
public static class PatientWithExtensionWithOneTypes extends Patient {
|
||||
@Child(name = "foo", type = { DateTimeType.class }, min = 0, max = 1)
|
||||
@Extension(url = "http://example.com/extension#foo", definedLocally = true, isModifier = false)
|
||||
@Description(shortDefinition = "Some description")
|
||||
private Type foo;
|
||||
|
||||
public Type getFoo() {
|
||||
return foo;
|
||||
}
|
||||
|
||||
public void setFoo(Type theFoo) {
|
||||
foo = theFoo;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtensionWithOneTypes() {
|
||||
PatientWithExtensionWithOneTypes pt = new PatientWithExtensionWithOneTypes();
|
||||
pt.setFoo(new DateTimeType("2011-01-01T00:00:00Z"));
|
||||
|
||||
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(pt);
|
||||
ourLog.info(encoded);
|
||||
|
||||
pt = ourCtx.newXmlParser().parseResource(PatientWithExtensionWithOneTypes.class, encoded);
|
||||
assertEquals("2011-01-01T00:00:00Z", ((DateTimeType)pt.getFoo()).getValueAsString());
|
||||
}
|
||||
|
||||
/**
|
||||
* See #364
|
||||
*/
|
||||
@Test
|
||||
public void testCustomTypeWithCustomDatatype() {
|
||||
FhirContext context = FhirContext.forR4();
|
||||
context.registerCustomType(CustomResource364R4.class);
|
||||
context.registerCustomType(CustomResource364CustomDate.class);
|
||||
IParser parser = context.newXmlParser();
|
||||
|
||||
CustomResource364R4 resource = new CustomResource364R4();
|
||||
resource.setBaseValues(new CustomResource364CustomDate().setDate(new DateTimeType("2016-05-13")));
|
||||
|
||||
String xml = parser.encodeResourceToString(resource);
|
||||
ourLog.info(xml);
|
||||
|
||||
//@formatter:on
|
||||
assertThat(xml, stringContainsInOrder(
|
||||
"<CustomResource xmlns=\"http://hl7.org/fhir\">",
|
||||
"<meta><profile value=\"http://hl7.org/fhir/profiles/custom-resource\"/></meta>",
|
||||
"<baseValueCustomDate><date value=\"2016-05-13\"/></baseValueCustomDate>",
|
||||
"</CustomResource>"));
|
||||
//@formatter:on
|
||||
|
||||
CustomResource364R4 parsedResource = parser.parseResource(CustomResource364R4.class, xml);
|
||||
assertEquals("2016-05-13", ((CustomResource364CustomDate) parsedResource.getBaseValues()).getDate().getValueAsString());
|
||||
}
|
||||
|
||||
/**
|
||||
* See #364
|
||||
*/
|
||||
@Test
|
||||
public void testCustomTypeWithPrimitiveType() {
|
||||
FhirContext context = FhirContext.forR4();
|
||||
context.registerCustomTypes(new ArrayList<Class<? extends IBase>>());
|
||||
|
||||
IParser parser = context.newXmlParser();
|
||||
|
||||
CustomResource364R4 resource = new CustomResource364R4();
|
||||
resource.setBaseValues(new StringType("2016-05-13"));
|
||||
|
||||
String xml = parser.encodeResourceToString(resource);
|
||||
|
||||
//@formatter:on
|
||||
assertThat(xml, stringContainsInOrder(
|
||||
"<CustomResource xmlns=\"http://hl7.org/fhir\">",
|
||||
"<meta><profile value=\"http://hl7.org/fhir/profiles/custom-resource\"/></meta>",
|
||||
"<baseValueString value=\"2016-05-13\"/>",
|
||||
"</CustomResource>"));
|
||||
//@formatter:on
|
||||
|
||||
CustomResource364R4 parsedResource = parser.parseResource(CustomResource364R4.class, xml);
|
||||
assertEquals("2016-05-13", ((StringType) parsedResource.getBaseValues()).getValueAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseBundleWithResourceDirective() {
|
||||
String input = createBundle(createResource(false), createResource(true));
|
||||
|
||||
FhirContext ctx = FhirContext.forR4();
|
||||
ctx.setDefaultTypeForProfile("http://example.com/foo", MyCustomPatient.class);
|
||||
|
||||
Bundle bundle = ctx.newXmlParser().parseResource(Bundle.class, input);
|
||||
|
||||
Patient res0 = (Patient) bundle.getEntry().get(0).getResource();
|
||||
assertEquals(0, res0.getMeta().getProfile().size());
|
||||
List<org.hl7.fhir.r4.model.Extension> exts = res0.getExtensionsByUrl("http://example.com/Weight");
|
||||
assertEquals(1, exts.size());
|
||||
assertEquals("185 cm", ((StringType) exts.get(0).getValue()).getValue());
|
||||
|
||||
MyCustomPatient res1 = (MyCustomPatient) bundle.getEntry().get(1).getResource();
|
||||
assertEquals(1, res1.getMeta().getProfile().size());
|
||||
assertEquals("http://example.com/foo", res1.getMeta().getProfile().get(0).getValue());
|
||||
exts = res1.getExtensionsByUrl("http://example.com/Weight");
|
||||
assertEquals(0, exts.size());
|
||||
assertEquals("185 cm", res1.getWeight().getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseResourceWithDirective() {
|
||||
String input = createResource(true);
|
||||
|
||||
FhirContext ctx = FhirContext.forR4();
|
||||
ctx.setDefaultTypeForProfile("http://example.com/foo", MyCustomPatient.class);
|
||||
|
||||
MyCustomPatient parsed = (MyCustomPatient) ctx.newXmlParser().parseResource(input);
|
||||
assertEquals(1, parsed.getMeta().getProfile().size());
|
||||
assertEquals("http://example.com/foo", parsed.getMeta().getProfile().get(0).getValue());
|
||||
|
||||
List<org.hl7.fhir.r4.model.Extension> exts = parsed.getExtensionsByUrl("http://example.com/Weight");
|
||||
assertEquals(0, exts.size());
|
||||
|
||||
assertEquals("185 cm", parsed.getWeight().getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseResourceWithNoDirective() {
|
||||
String input = createResource(true);
|
||||
|
||||
FhirContext ctx = FhirContext.forR4();
|
||||
Patient parsed = (Patient) ctx.newXmlParser().parseResource(input);
|
||||
assertEquals(1, parsed.getMeta().getProfile().size());
|
||||
assertEquals("http://example.com/foo", parsed.getMeta().getProfile().get(0).getValue());
|
||||
|
||||
List<org.hl7.fhir.r4.model.Extension> exts = parsed.getExtensionsByUrl("http://example.com/Weight");
|
||||
assertEquals(1, exts.size());
|
||||
assertEquals("185 cm", ((StringType) exts.get(0).getValue()).getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAccessEmptyMetaLists() {
|
||||
Patient p = new Patient();
|
||||
assertThat(p.getMeta().getProfile(), empty());
|
||||
assertThat(p.getMeta().getFormatCommentsPost(), empty());
|
||||
assertThat(p.getMeta().getFormatCommentsPre(), empty());
|
||||
assertThat(p.getMeta().getLastUpdated(), nullValue());
|
||||
assertThat(p.getMeta().getSecurity(), empty());
|
||||
assertThat(p.getMeta().getSecurity("foo", "bar"), nullValue());
|
||||
assertThat(p.getMeta().getTag(), empty());
|
||||
assertThat(p.getMeta().getTag("foo", "bar"), nullValue());
|
||||
assertThat(p.getMeta().getVersionId(), nullValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeCompleteMetaLists() {
|
||||
Patient p = new Patient();
|
||||
p.getMeta().addProfile("http://foo/profile1");
|
||||
p.getMeta().addProfile("http://foo/profile2");
|
||||
p.getMeta().addSecurity().setSystem("SEC_S1").setCode("SEC_C1").setDisplay("SED_D1");
|
||||
p.getMeta().addSecurity().setSystem("SEC_S2").setCode("SEC_C2").setDisplay("SED_D2");
|
||||
p.getMeta().addTag().setSystem("TAG_S1").setCode("TAG_C1").setDisplay("TAG_D1");
|
||||
p.getMeta().addTag().setSystem("TAG_S2").setCode("TAG_C2").setDisplay("TAG_D2");
|
||||
|
||||
String out = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
|
||||
ourLog.info(out);
|
||||
|
||||
//@formatter:off
|
||||
assertThat(out, stringContainsInOrder(
|
||||
"<meta>",
|
||||
"<profile value=\"http://foo/profile1\"/>",
|
||||
"<profile value=\"http://foo/profile2\"/>",
|
||||
"<security>",
|
||||
"<system value=\"SEC_S1\"/>",
|
||||
"<code value=\"SEC_C1\"/>",
|
||||
"<display value=\"SED_D1\"/>",
|
||||
"</security>",
|
||||
"<security>",
|
||||
"<system value=\"SEC_S2\"/>",
|
||||
"<code value=\"SEC_C2\"/>",
|
||||
"<display value=\"SED_D2\"/>",
|
||||
"</security>",
|
||||
"<tag>",
|
||||
"<system value=\"TAG_S1\"/>",
|
||||
"<display value=\"TAG_D1\"/>",
|
||||
"</tag>",
|
||||
"<tag>",
|
||||
"<system value=\"TAG_S2\"/>",
|
||||
"<display value=\"TAG_D2\"/>",
|
||||
"</tag>",
|
||||
"</meta>"));
|
||||
//@formatter:on
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeWithCustomType() {
|
||||
|
||||
MyCustomPatient patient = new MyCustomPatient();
|
||||
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("1234");
|
||||
patient.addName().setFamily("Rossi").addGiven("Mario");
|
||||
patient.setInsulinLevel(new Quantity());
|
||||
patient.setGlucoseLevel(new Quantity());
|
||||
patient.setHbA1c(new Quantity());
|
||||
patient.setBloodPressure(new Quantity());
|
||||
patient.setCholesterol(new Quantity());
|
||||
patient.setWeight(new StringDt("80 kg"));
|
||||
patient.setWeight(new StringDt("185 cm"));
|
||||
patient.setCheckDates(new ArrayList<DateTimeDt>());
|
||||
patient.getCheckDates().add(new DateTimeDt("2014-01-26T11:11:11"));
|
||||
|
||||
ourCtx.setAddProfileTagWhenEncoding(AddProfileTagEnum.ONLY_FOR_CUSTOM);
|
||||
IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
|
||||
String messageString = p.encodeResourceToString(patient);
|
||||
|
||||
ourLog.info(messageString);
|
||||
|
||||
//@formatter:off
|
||||
assertThat(messageString, stringContainsInOrder(
|
||||
"<meta>",
|
||||
"<profile value=\"http://example.com/foo\"/>",
|
||||
"</meta>"));
|
||||
//@formatter:on
|
||||
|
||||
//@formatter:off
|
||||
assertThat(messageString, not(stringContainsInOrder(
|
||||
"<meta>",
|
||||
"<profile value=\"http://example.com/foo\"", "/>",
|
||||
"<profile value=\"http://example.com/foo\"/>",
|
||||
"</meta>")));
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeWithCustomTypeAndAutoInsertedProfile() {
|
||||
|
||||
MyCustomPatient patient = new MyCustomPatient();
|
||||
|
||||
patient.getMeta().addProfile("http://example.com/foo");
|
||||
patient.getMeta().addProfile("http://example.com/bar");
|
||||
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("1234");
|
||||
patient.addName().setFamily("Rossi").addGiven("Mario");
|
||||
patient.setInsulinLevel(new Quantity());
|
||||
patient.setGlucoseLevel(new Quantity());
|
||||
patient.setHbA1c(new Quantity());
|
||||
patient.setBloodPressure(new Quantity());
|
||||
patient.setCholesterol(new Quantity());
|
||||
patient.setWeight(new StringDt("80 kg"));
|
||||
patient.setWeight(new StringDt("185 cm"));
|
||||
patient.setCheckDates(new ArrayList<DateTimeDt>());
|
||||
patient.getCheckDates().add(new DateTimeDt("2014-01-26T11:11:11"));
|
||||
|
||||
ourCtx.setAddProfileTagWhenEncoding(AddProfileTagEnum.ONLY_FOR_CUSTOM);
|
||||
IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
|
||||
String messageString = p.encodeResourceToString(patient);
|
||||
|
||||
ourLog.info(messageString);
|
||||
|
||||
//@formatter:off
|
||||
assertThat(messageString, stringContainsInOrder(
|
||||
"<meta>",
|
||||
"<profile value=\"http://example.com/foo\"/>",
|
||||
"<profile value=\"http://example.com/bar\"/>",
|
||||
"</meta>"));
|
||||
//@formatter:on
|
||||
|
||||
//@formatter:off
|
||||
assertThat(messageString, not(stringContainsInOrder(
|
||||
"<meta>",
|
||||
"<profile value=\"http://example.com/foo\"", "/>",
|
||||
"<profile value=\"http://example.com/foo\"/>",
|
||||
"</meta>")));
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
/**
|
||||
* See #318
|
||||
*/
|
||||
@Test
|
||||
public void testParseResourceWithContainedResourcesWithProfile() {
|
||||
//@formatter:off
|
||||
String input = "<MedicationRequest xmlns=\"http://hl7.org/fhir\">"
|
||||
+ "<id value=\"44cfa24c-52e1-a8ff-8428-4e7ce1165460-local\"/> "
|
||||
+ "<meta> "
|
||||
+ "<profile value=\"http://fhir.something.com/StructureDefinition/our-medication-order\"/> "
|
||||
+ "</meta> "
|
||||
+ "<contained> "
|
||||
+ "<Medication xmlns=\"http://hl7.org/fhir\"> "
|
||||
+ "<id value=\"1\"/>"
|
||||
+ "<meta> "
|
||||
+ "<profile value=\"http://fhir.something.com/StructureDefinition/our-medication\"/> "
|
||||
+ "</meta> "
|
||||
+ "<code> "
|
||||
+ "<text value=\"medication\"/> "
|
||||
+ "</code> "
|
||||
+ "</Medication> "
|
||||
+ "</contained> "
|
||||
+ "<medication> "
|
||||
+ "<reference value=\"#1\"/> "
|
||||
+ "</medication> "
|
||||
+ "</MedicationRequest>";
|
||||
//@formatter:on
|
||||
|
||||
FhirContext ctx = FhirContext.forR4();
|
||||
ctx.setDefaultTypeForProfile("http://fhir.something.com/StructureDefinition/our-medication", MyMedication.class);
|
||||
|
||||
MedicationRequest mo = ctx.newXmlParser().parseResource(MedicationRequest.class, input);
|
||||
assertEquals(MyMedication.class, mo.getContained().get(0).getClass());
|
||||
}
|
||||
|
||||
public static String createBundle(String... theResources) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("<Bundle xmlns=\"http://hl7.org/fhir\">\n");
|
||||
for (String next : theResources) {
|
||||
b.append(" <entry>\n");
|
||||
b.append(" <resource>\n");
|
||||
b.append(next);
|
||||
b.append(" </resource>\n");
|
||||
b.append(" </entry>\n");
|
||||
}
|
||||
b.append("</Bundle>");
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
public static String createResource(boolean theWithProfile) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("<Patient xmlns=\"http://hl7.org/fhir\">\n");
|
||||
if (theWithProfile) {
|
||||
b.append(" <meta>\n");
|
||||
b.append(" <profile value=\"http://example.com/foo\"/>\n");
|
||||
b.append(" </meta>\n");
|
||||
}
|
||||
b.append(" <extension url=\"http://example.com/BloodPressure\">\n");
|
||||
b.append(" <valueQuantity>\n");
|
||||
b.append(" <value value=\"110\"/>\n");
|
||||
b.append(" <system value=\"http://unitsofmeasure.org\"/>\n");
|
||||
b.append(" <code value=\"mmHg\"/>\n");
|
||||
b.append(" </valueQuantity>\n");
|
||||
b.append(" </extension>\n");
|
||||
b.append(" <modifierExtension url=\"http://example.com/diabetes2\">\n");
|
||||
b.append(" <valueDateTime value=\"2010-01-02\"/>\n");
|
||||
b.append(" </modifierExtension>\n");
|
||||
b.append(" <modifierExtension url=\"http://example.com/diabetes2\">\n");
|
||||
b.append(" <valueDateTime value=\"2014-01-26T11:11:11\"/>\n");
|
||||
b.append(" </modifierExtension>\n");
|
||||
b.append(" <extension url=\"http://example.com/Cholesterol\">\n");
|
||||
b.append(" <valueQuantity>\n");
|
||||
b.append(" <value value=\"2\"/>\n");
|
||||
b.append(" <system value=\"http://unitsofmeasure.org\"/>\n");
|
||||
b.append(" <code value=\"mmol/l\"/>\n");
|
||||
b.append(" </valueQuantity>\n");
|
||||
b.append(" </extension>\n");
|
||||
b.append(" <extension url=\"http://example.com/Glucose\">\n");
|
||||
b.append(" <valueQuantity>\n");
|
||||
b.append(" <value value=\"95\"/>\n");
|
||||
b.append(" <system value=\"http://unitsofmeasure.org\"/>\n");
|
||||
b.append(" <code value=\"mg/dl\"/>\n");
|
||||
b.append(" </valueQuantity>\n");
|
||||
b.append(" </extension>\n");
|
||||
b.append(" <extension url=\"http://example.com/HbA1c\">\n");
|
||||
b.append(" <valueQuantity>\n");
|
||||
b.append(" <value value=\"48\"/>\n");
|
||||
b.append(" <system value=\"http://unitsofmeasure.org\"/>\n");
|
||||
b.append(" <code value=\"mmol/mol\"/>\n");
|
||||
b.append(" </valueQuantity>\n");
|
||||
b.append(" </extension>\n");
|
||||
b.append(" <extension url=\"http://example.com/Insuline\">\n");
|
||||
b.append(" <valueQuantity>\n");
|
||||
b.append(" <value value=\"125\"/>\n");
|
||||
b.append(" <system value=\"http://unitsofmeasure.org\"/>\n");
|
||||
b.append(" <code value=\"pmol/l\"/>\n");
|
||||
b.append(" </valueQuantity>\n");
|
||||
b.append(" </extension>\n");
|
||||
b.append(" <extension url=\"http://example.com/Weight\">\n");
|
||||
b.append(" <valueString value=\"185 cm\"/>\n");
|
||||
b.append(" </extension>\n");
|
||||
b.append(" <identifier>\n");
|
||||
b.append(" <system value=\"urn:system\"/>\n");
|
||||
b.append(" <value value=\"1234\"/>\n");
|
||||
b.append(" </identifier>\n");
|
||||
b.append(" <name>\n");
|
||||
b.append(" <family value=\"Rossi\"/>\n");
|
||||
b.append(" <given value=\"Mario\"/>\n");
|
||||
b.append(" </name>\n");
|
||||
b.append("</Patient>");
|
||||
String input = b.toString();
|
||||
return input;
|
||||
}
|
||||
|
||||
@ResourceDef(name = "Patient", profile = "http://example.com/foo")
|
||||
public static class MyCustomPatient extends Patient {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Child(name = "bloodPressure") // once every 3 month. The average target is 130/80 mmHg or less
|
||||
@Extension(url = "http://example.com/BloodPressure", definedLocally = false, isModifier = false)
|
||||
@Description(shortDefinition = "The value of the patient's blood pressure")
|
||||
private Quantity myBloodPressure;
|
||||
|
||||
// Dates of periodic tests
|
||||
@Child(name = "CheckDates", max = Child.MAX_UNLIMITED)
|
||||
@Extension(url = "http://example.com/diabetes2", definedLocally = false, isModifier = true)
|
||||
@Description(shortDefinition = "Dates of periodic tests")
|
||||
private List<DateTimeDt> myCheckDates;
|
||||
|
||||
@Child(name = "cholesterol") // once a year. The target is triglycerides =< 2 mmol/l e cholesterol =< 4 mmol/l
|
||||
@Extension(url = "http://example.com/Cholesterol", definedLocally = false, isModifier = false)
|
||||
@Description(shortDefinition = "The value of the patient's cholesterol")
|
||||
private Quantity myCholesterol;
|
||||
|
||||
@Child(name = "glucoseLevel") // fingerprick test
|
||||
@Extension(url = "http://example.com/Glucose", definedLocally = false, isModifier = false)
|
||||
@Description(shortDefinition = "The value of the patient's blood glucose")
|
||||
private Quantity myGlucoseLevel;
|
||||
|
||||
// Periodic Tests
|
||||
@Child(name = "hbA1c") // once every 6 month. The average target is 53 mmol/mol (or 7%) or less.
|
||||
@Extension(url = "http://example.com/HbA1c", definedLocally = false, isModifier = false)
|
||||
@Description(shortDefinition = "The value of the patient's glucose")
|
||||
private Quantity myHbA1c;
|
||||
|
||||
@Child(name = "Height")
|
||||
@Extension(url = "http://example.com/Height", definedLocally = false, isModifier = false)
|
||||
@Description(shortDefinition = "The patient's height in cm")
|
||||
private StringDt myHeight;
|
||||
|
||||
@Child(name = "insulinLevel") // Normal range is [43,208] pmol/l
|
||||
@Extension(url = "http://example.com/Insuline", definedLocally = false, isModifier = false)
|
||||
@Description(shortDefinition = "The value of the patient's insulin")
|
||||
private Quantity myInsulinLevel;
|
||||
|
||||
// Other parameters
|
||||
@Child(name = "weight")
|
||||
@Extension(url = "http://example.com/Weight", definedLocally = false, isModifier = false)
|
||||
@Description(shortDefinition = "The patient's weight in Kg")
|
||||
private StringDt myWeight;
|
||||
|
||||
public Quantity Cholesterol() {
|
||||
if (myCholesterol == null) {
|
||||
myCholesterol = new Quantity();
|
||||
}
|
||||
myCholesterol.getValue();
|
||||
myCholesterol.getSystem();
|
||||
myCholesterol.getCode();
|
||||
|
||||
return myCholesterol;
|
||||
}
|
||||
|
||||
public Quantity getBloodPressure() {
|
||||
if (myBloodPressure == null) {
|
||||
myBloodPressure = new Quantity();
|
||||
}
|
||||
myBloodPressure.getValue();
|
||||
myBloodPressure.getSystem();
|
||||
myBloodPressure.getCode();
|
||||
|
||||
return myBloodPressure;
|
||||
}
|
||||
|
||||
public List<DateTimeDt> getCheckDates() {
|
||||
if (myCheckDates == null) {
|
||||
myCheckDates = new ArrayList<DateTimeDt>();
|
||||
}
|
||||
return myCheckDates;
|
||||
}
|
||||
|
||||
public Quantity getGlucoseLevel() {
|
||||
if (myGlucoseLevel == null) {
|
||||
myGlucoseLevel = new Quantity();
|
||||
}
|
||||
myGlucoseLevel.getValue();
|
||||
myGlucoseLevel.getSystem();
|
||||
myGlucoseLevel.getCode();
|
||||
|
||||
return myGlucoseLevel;
|
||||
}
|
||||
|
||||
public Quantity getHbA1c() {
|
||||
if (myHbA1c == null) {
|
||||
myHbA1c = new Quantity();
|
||||
}
|
||||
myHbA1c.getValue();
|
||||
myHbA1c.getSystem();
|
||||
myHbA1c.getCode();
|
||||
|
||||
return myHbA1c;
|
||||
}
|
||||
|
||||
public StringDt getHeight() {
|
||||
if (myHeight == null) {
|
||||
myHeight = new StringDt();
|
||||
}
|
||||
return myHeight;
|
||||
}
|
||||
|
||||
public Quantity getInsulinLevel() {
|
||||
if (myInsulinLevel == null) {
|
||||
myInsulinLevel = new Quantity();
|
||||
}
|
||||
myInsulinLevel.getValue();
|
||||
myInsulinLevel.getSystem();
|
||||
myInsulinLevel.getCode();
|
||||
|
||||
return myInsulinLevel;
|
||||
}
|
||||
|
||||
public StringDt getWeight() {
|
||||
if (myWeight == null) {
|
||||
myWeight = new StringDt();
|
||||
}
|
||||
return myWeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return super.isEmpty() && ElementUtil.isEmpty(myInsulinLevel, myGlucoseLevel, myHbA1c, myBloodPressure, myCholesterol, myWeight, myHeight, myCheckDates);
|
||||
}
|
||||
|
||||
public void setBloodPressure(Quantity bloodPressure) {
|
||||
myBloodPressure = bloodPressure;
|
||||
myBloodPressure.setValue(110);
|
||||
myBloodPressure.setSystem("http://unitsofmeasure.org");
|
||||
myBloodPressure.setCode("mmHg");
|
||||
}
|
||||
|
||||
public void setCheckDates(List<DateTimeDt> theCheckDates) {
|
||||
myCheckDates = theCheckDates;
|
||||
myCheckDates.add(new DateTimeDt("2010-01-02"));
|
||||
}
|
||||
|
||||
public void setCholesterol(Quantity cholesterol) {
|
||||
myCholesterol = cholesterol;
|
||||
myCholesterol.setValue(2);
|
||||
myCholesterol.setSystem("http://unitsofmeasure.org");
|
||||
myCholesterol.setCode("mmol/l");
|
||||
}
|
||||
|
||||
public void setGlucoseLevel(Quantity glucoseLevel) {
|
||||
myGlucoseLevel = glucoseLevel;
|
||||
myGlucoseLevel.setValue(95);
|
||||
myGlucoseLevel.setSystem("http://unitsofmeasure.org");
|
||||
myGlucoseLevel.setCode("mg/dl");
|
||||
}
|
||||
|
||||
public void setHbA1c(Quantity hba1c) {
|
||||
myHbA1c = hba1c;
|
||||
myHbA1c.setValue(48);
|
||||
myHbA1c.setSystem("http://unitsofmeasure.org");
|
||||
myHbA1c.setCode("mmol/mol");
|
||||
}
|
||||
|
||||
public void setHeight(StringDt height) {
|
||||
myHeight = height;
|
||||
}
|
||||
|
||||
// Setter/Getter methods
|
||||
public void setInsulinLevel(Quantity insulinLevel) {
|
||||
myInsulinLevel = insulinLevel;
|
||||
myInsulinLevel.setValue(125);
|
||||
myInsulinLevel.setSystem("http://unitsofmeasure.org");
|
||||
myInsulinLevel.setCode("pmol/l");
|
||||
}
|
||||
|
||||
public void setWeight(StringDt weight) {
|
||||
myWeight = weight;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ResourceDef()
|
||||
public static class MyMedication extends Medication {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
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.*;
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.message.BasicStatusLine;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.*;
|
||||
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.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
/**
|
||||
* http://gforge.hl7.org/gf/project/fhir/tracker/?action=TrackerItemEdit&tracker_id=677&tracker_item_id=10199
|
||||
*/
|
||||
public class ClientMimetypeR4Test {
|
||||
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());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMimetypeXmlNew() throws Exception {
|
||||
String requestCt = Constants.CT_FHIR_XML_NEW;
|
||||
|
||||
ArgumentCaptor<HttpUriRequest> capt = prepareMimetypePostTest(requestCt, true);
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.getText().setDivAsString("A PATIENT");
|
||||
|
||||
MethodOutcome outcome = client.create().resource(pt).execute();
|
||||
|
||||
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">FINAL VALUE</div>", ((Patient) outcome.getResource()).getText().getDivAsString());
|
||||
assertEquals("http://example.com/fhir/Patient", capt.getAllValues().get(0).getURI().toASCIIString());
|
||||
assertEquals(Constants.CT_FHIR_XML_NEW, capt.getAllValues().get(0).getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
||||
assertEquals(Constants.HEADER_ACCEPT_VALUE_XML_NON_LEGACY, capt.getAllValues().get(0).getFirstHeader("accept").getValue());
|
||||
assertEquals("<Patient xmlns=\"http://hl7.org/fhir\"><text><div xmlns=\"http://www.w3.org/1999/xhtml\">A PATIENT</div></text></Patient>", extractBodyAsString(capt));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMimetypeXmlLegacy() throws Exception {
|
||||
String requestCt = Constants.CT_FHIR_XML;
|
||||
|
||||
ArgumentCaptor<HttpUriRequest> capt = prepareMimetypePostTest(requestCt, true);
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.getText().setDivAsString("A PATIENT");
|
||||
|
||||
MethodOutcome outcome = client.create().resource(pt).execute();
|
||||
|
||||
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">FINAL VALUE</div>", ((Patient) outcome.getResource()).getText().getDivAsString());
|
||||
assertEquals("http://example.com/fhir/Patient", capt.getAllValues().get(0).getURI().toASCIIString());
|
||||
assertEquals(Constants.CT_FHIR_XML_NEW, capt.getAllValues().get(0).getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
||||
assertEquals(Constants.HEADER_ACCEPT_VALUE_XML_NON_LEGACY, capt.getAllValues().get(0).getFirstHeader("accept").getValue());
|
||||
assertEquals("<Patient xmlns=\"http://hl7.org/fhir\"><text><div xmlns=\"http://www.w3.org/1999/xhtml\">A PATIENT</div></text></Patient>", extractBodyAsString(capt));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMimetypeJsonNew() throws Exception {
|
||||
String requestCt = Constants.CT_FHIR_JSON_NEW;
|
||||
|
||||
ArgumentCaptor<HttpUriRequest> capt = prepareMimetypePostTest(requestCt, false);
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.getText().setDivAsString("A PATIENT");
|
||||
|
||||
MethodOutcome outcome = client.create().resource(pt).encodedJson().execute();
|
||||
|
||||
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">FINAL VALUE</div>", ((Patient) outcome.getResource()).getText().getDivAsString());
|
||||
assertEquals("http://example.com/fhir/Patient", capt.getAllValues().get(0).getURI().toASCIIString());
|
||||
assertEquals(Constants.CT_FHIR_JSON_NEW, capt.getAllValues().get(0).getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
||||
assertEquals(Constants.HEADER_ACCEPT_VALUE_JSON_NON_LEGACY, capt.getAllValues().get(0).getFirstHeader("accept").getValue());
|
||||
assertEquals("{\"resourceType\":\"Patient\",\"text\":{\"div\":\"<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\">A PATIENT</div>\"}}", extractBodyAsString(capt));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMimetypeJsonLegacy() throws Exception {
|
||||
String requestCt = Constants.CT_FHIR_JSON;
|
||||
|
||||
ArgumentCaptor<HttpUriRequest> capt = prepareMimetypePostTest(requestCt, false);
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.getText().setDivAsString("A PATIENT");
|
||||
|
||||
MethodOutcome outcome = client.create().resource(pt).encodedJson().execute();
|
||||
|
||||
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">FINAL VALUE</div>", ((Patient) outcome.getResource()).getText().getDivAsString());
|
||||
assertEquals("http://example.com/fhir/Patient", capt.getAllValues().get(0).getURI().toASCIIString());
|
||||
assertEquals(Constants.CT_FHIR_JSON_NEW, capt.getAllValues().get(0).getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
||||
assertEquals(Constants.HEADER_ACCEPT_VALUE_JSON_NON_LEGACY, capt.getAllValues().get(0).getFirstHeader("accept").getValue());
|
||||
assertEquals("{\"resourceType\":\"Patient\",\"text\":{\"div\":\"<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\">A PATIENT</div>\"}}", extractBodyAsString(capt));
|
||||
}
|
||||
|
||||
private String extractBodyAsString(ArgumentCaptor<HttpUriRequest> capt) throws IOException {
|
||||
String body = IOUtils.toString(((HttpEntityEnclosingRequestBase) capt.getAllValues().get(0)).getEntity().getContent(), "UTF-8");
|
||||
return body;
|
||||
}
|
||||
|
||||
private ArgumentCaptor<HttpUriRequest> prepareMimetypePostTest(String requestCt, boolean theXml) throws IOException, ClientProtocolException {
|
||||
final IParser p = theXml ? ourCtx.newXmlParser() : ourCtx.newJsonParser();
|
||||
|
||||
final Patient resp1 = new Patient();
|
||||
resp1.getText().setDivAsString("FINAL VALUE");
|
||||
|
||||
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.getAllHeaders()).thenAnswer(new Answer<Header[]>() {
|
||||
@Override
|
||||
public Header[] answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
return new Header[] { new BasicHeader(Constants.HEADER_LOCATION, "http://foo.com/base/Patient/222/_history/3") };
|
||||
}
|
||||
});
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", requestCt + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
|
||||
@Override
|
||||
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
return new ReaderInputStream(new StringReader(p.encodeResourceToString(resp1)), Charset.forName("UTF-8"));
|
||||
}
|
||||
});
|
||||
return capt;
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
ourCtx = FhirContext.forR4();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
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.StringReader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
|
||||
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.HttpUriRequest;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.message.BasicStatusLine;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Organization;
|
||||
import org.junit.*;
|
||||
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.api.Constants;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.param.DateParam;
|
||||
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class ClientWithCustomTypeR4Test {
|
||||
private static FhirContext ourCtx;
|
||||
private HttpClient myHttpClient;
|
||||
private HttpResponse myHttpResponse;
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@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());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadCustomType() throws Exception {
|
||||
IParser p = ourCtx.newXmlParser();
|
||||
|
||||
MyPatientWithExtensions response = new MyPatientWithExtensions();
|
||||
response.addName().setFamily("FAMILY");
|
||||
response.getStringExt().setValue("STRINGVAL");
|
||||
response.getDateExt().setValueAsString("2011-01-02");
|
||||
final String respString = p.encodeResourceToString(response);
|
||||
|
||||
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"));
|
||||
}
|
||||
});
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
//@formatter:off
|
||||
MyPatientWithExtensions value = client
|
||||
.read()
|
||||
.resource(MyPatientWithExtensions.class)
|
||||
.withId("123")
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
HttpUriRequest request = capt.getAllValues().get(0);
|
||||
|
||||
assertEquals("http://example.com/fhir/Patient/123", request.getURI().toASCIIString());
|
||||
assertEquals("GET", request.getMethod());
|
||||
|
||||
assertEquals(1, value.getName().size());
|
||||
assertEquals("FAMILY", value.getName().get(0).getFamily());
|
||||
assertEquals("STRINGVAL", value.getStringExt().getValue());
|
||||
assertEquals("2011-01-02", value.getDateExt().getValueAsString());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithGenericReturnType() throws Exception {
|
||||
|
||||
final Bundle bundle = new Bundle();
|
||||
|
||||
final ExtendedPatient patient = new ExtendedPatient();
|
||||
patient.addIdentifier().setValue("PRP1660");
|
||||
bundle.addEntry().setResource(patient);
|
||||
|
||||
final Organization org = new Organization();
|
||||
org.setName("FOO");
|
||||
patient.getManagingOrganization().setResource(org);
|
||||
|
||||
final FhirContext ctx = FhirContext.forR4();
|
||||
ctx.setDefaultTypeForProfile(ExtendedPatient.HTTP_FOO_PROFILES_PROFILE, ExtendedPatient.class);
|
||||
ctx.getRestfulClientFactory().setHttpClient(myHttpClient);
|
||||
ctx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
|
||||
String msg = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(bundle);
|
||||
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
|
||||
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")));
|
||||
|
||||
// httpResponse = new BasicHttpResponse(statusline, catalog, locale)
|
||||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
|
||||
ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo");
|
||||
List<IBaseResource> response = client.getPatientByDobWithGenericResourceReturnType(new DateParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, "2011-01-02"));
|
||||
|
||||
assertEquals("http://foo/Patient?birthdate=ge2011-01-02", capt.getValue().getURI().toString());
|
||||
ExtendedPatient patientResp = (ExtendedPatient) response.get(0);
|
||||
assertEquals("PRP1660", patientResp.getIdentifier().get(0).getValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithGenericReturnType2() throws Exception {
|
||||
|
||||
final Bundle bundle = new Bundle();
|
||||
|
||||
final ExtendedPatient patient = new ExtendedPatient();
|
||||
patient.addIdentifier().setValue("PRP1660");
|
||||
bundle.addEntry().setResource(patient);
|
||||
|
||||
final Organization org = new Organization();
|
||||
org.setName("FOO");
|
||||
patient.getManagingOrganization().setResource(org);
|
||||
|
||||
final FhirContext ctx = FhirContext.forR4();
|
||||
ctx.setDefaultTypeForProfile(ExtendedPatient.HTTP_FOO_PROFILES_PROFILE, ExtendedPatient.class);
|
||||
ctx.getRestfulClientFactory().setHttpClient(myHttpClient);
|
||||
ctx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
|
||||
String msg = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(bundle);
|
||||
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
|
||||
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")));
|
||||
|
||||
// httpResponse = new BasicHttpResponse(statusline, catalog, locale)
|
||||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
|
||||
ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo");
|
||||
List<IAnyResource> response = client.getPatientByDobWithGenericResourceReturnType2(new DateParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, "2011-01-02"));
|
||||
|
||||
assertEquals("http://foo/Patient?birthdate=ge2011-01-02", capt.getValue().getURI().toString());
|
||||
ExtendedPatient patientResp = (ExtendedPatient) response.get(0);
|
||||
assertEquals("PRP1660", patientResp.getIdentifier().get(0).getValue());
|
||||
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
ourCtx = FhirContext.forR4();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package ca.uhn.fhir.rest.client;
|
||||
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
|
||||
import ca.uhn.fhir.model.api.annotation.*;
|
||||
|
||||
@ResourceDef(name = "Patient", profile = ExtendedPatient.HTTP_FOO_PROFILES_PROFILE)
|
||||
public class ExtendedPatient extends Patient {
|
||||
|
||||
static final String HTTP_FOO_PROFILES_PROFILE = "http://foo/profiles/Profile";
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* Each extension is defined in a field. Any valid HAPI Data Type
|
||||
* can be used for the field type. Note that the [name=""] attribute
|
||||
* in the @Child annotation needs to match the name for the bean accessor
|
||||
* and mutator methods.
|
||||
*/
|
||||
@Child(name = "petName")
|
||||
@Extension(url = "http://example.com/dontuse#petname", definedLocally = false, isModifier = false)
|
||||
@Description(shortDefinition = "The name of the patient's favourite pet")
|
||||
private StringType myPetName;
|
||||
|
||||
public StringType getPetName() {
|
||||
if (myPetName == null) {
|
||||
myPetName = new StringType();
|
||||
}
|
||||
return myPetName;
|
||||
}
|
||||
|
||||
public void setPetName(StringType thePetName) {
|
||||
myPetName = thePetName;
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,22 @@
|
||||
package ca.uhn.fhir.rest.client;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
|
||||
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.client.api.IBasicClient;
|
||||
import ca.uhn.fhir.rest.param.DateParam;
|
||||
|
||||
public interface ITestClient extends IBasicClient {
|
||||
|
||||
@Search(type=ExtendedPatient.class)
|
||||
public List<IBaseResource> getPatientByDobWithGenericResourceReturnType(@RequiredParam(name=Patient.SP_BIRTHDATE) DateParam theBirthDate);
|
||||
|
||||
@Search(type=ExtendedPatient.class)
|
||||
public List<IAnyResource> getPatientByDobWithGenericResourceReturnType2(@RequiredParam(name=Patient.SP_BIRTHDATE) DateParam theBirthDate);
|
||||
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
package ca.uhn.fhir.rest.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
|
||||
import ca.uhn.fhir.model.api.annotation.*;
|
||||
import ca.uhn.fhir.model.api.annotation.Extension;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
|
||||
|
||||
@ResourceDef(name="Patient", profile="http://example.com/StructureDefinition/patient_with_extensions")
|
||||
public class MyPatientWithExtensions extends DomainResource {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Extension(url = "http://example.com/ext/date", definedLocally = false, isModifier = true)
|
||||
@Child(name = "modExt")
|
||||
private DateType myDateExt;
|
||||
|
||||
@Extension(url = "http://example.com/ext/string", definedLocally = false, isModifier = false)
|
||||
@Child(name = "extAtt")
|
||||
private StringType myStringExt;
|
||||
|
||||
@Child(name = "name", type = {HumanName.class}, min=0, max=Child.MAX_UNLIMITED, modifier=false, summary=true)
|
||||
@Description(shortDefinition="A name associated with the patient", formalDefinition="A name associated with the individual." )
|
||||
private List<HumanName> myName;
|
||||
|
||||
|
||||
public List<HumanName> getName() {
|
||||
if (myName == null) {
|
||||
myName = new ArrayList<HumanName>();
|
||||
}
|
||||
return myName;
|
||||
}
|
||||
|
||||
public void setName(List<HumanName> theName) {
|
||||
myName = theName;
|
||||
}
|
||||
|
||||
public DateType getDateExt() {
|
||||
if (myDateExt == null) {
|
||||
myDateExt = new DateType();
|
||||
}
|
||||
return myDateExt;
|
||||
}
|
||||
|
||||
public StringType getStringExt() {
|
||||
if (myStringExt == null) {
|
||||
myStringExt = new StringType();
|
||||
}
|
||||
return myStringExt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return super.isEmpty() && ElementUtil.isEmpty(myStringExt, myDateExt);
|
||||
}
|
||||
|
||||
public void setDateExt(DateType theDateExt) {
|
||||
myDateExt = theDateExt;
|
||||
}
|
||||
|
||||
public void setStringExt(StringType theStringExt) {
|
||||
myStringExt = theStringExt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResource copy() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceType getResourceType() {
|
||||
return ResourceType.Patient;
|
||||
}
|
||||
|
||||
public HumanName addName() {
|
||||
HumanName retVal = new HumanName();
|
||||
getName().add(retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,186 @@
|
||||
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 java.util.List;
|
||||
|
||||
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.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.junit.*;
|
||||
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.*;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
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.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.client.impl.BaseClient;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class NonGenericClientR4Test {
|
||||
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 testValidateCustomTypeFromClientSearch() throws Exception {
|
||||
IParser p = ourCtx.newXmlParser();
|
||||
|
||||
Bundle b = new Bundle();
|
||||
|
||||
MyPatientWithExtensions patient = new MyPatientWithExtensions();
|
||||
patient.setId("123");
|
||||
patient.getText().setDivAsString("OK!");
|
||||
b.addEntry().setResource(patient);
|
||||
|
||||
|
||||
final String respString = p.encodeResourceToString(b);
|
||||
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"));
|
||||
}
|
||||
});
|
||||
|
||||
IClientWithCustomType client = ourCtx.newRestfulClient(IClientWithCustomType.class, "http://example.com/fhir");
|
||||
List<MyPatientWithExtensions> list = client.search();
|
||||
|
||||
assertEquals(1, list.size());
|
||||
assertEquals(MyPatientWithExtensions.class, list.get(0).getClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCustomTypeFromClientRead() throws Exception {
|
||||
IParser p = ourCtx.newXmlParser();
|
||||
|
||||
MyPatientWithExtensions patient = new MyPatientWithExtensions();
|
||||
patient.setId("123");
|
||||
patient.getText().setDivAsString("OK!");
|
||||
|
||||
final String respString = p.encodeResourceToString(patient);
|
||||
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"));
|
||||
}
|
||||
});
|
||||
|
||||
IClientWithCustomType client = ourCtx.newRestfulClient(IClientWithCustomType.class, "http://example.com/fhir");
|
||||
MyPatientWithExtensions read = client.read(new IdType("1"));
|
||||
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">OK!</div>", read.getText().getDivAsString());
|
||||
}
|
||||
|
||||
@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().setFamily("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);
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
ourCtx = FhirContext.forR4();
|
||||
}
|
||||
|
||||
private interface IClient extends IRestfulClient {
|
||||
|
||||
@Validate
|
||||
MethodOutcome validate(@ResourceParam IBaseResource theResource, @Validate.Mode ValidationModeEnum theMode, @Validate.Profile String theProfile);
|
||||
|
||||
}
|
||||
|
||||
private interface IClientWithCustomType extends IRestfulClient {
|
||||
|
||||
@Search
|
||||
List<MyPatientWithExtensions> search();
|
||||
|
||||
@Read
|
||||
MyPatientWithExtensions read(@IdParam IdType theId);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,188 @@
|
||||
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.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
|
||||
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.*;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.message.BasicStatusLine;
|
||||
import org.hl7.fhir.r4.model.Parameters;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.junit.*;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.annotation.Operation;
|
||||
import ca.uhn.fhir.rest.annotation.OperationParam;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.client.api.*;
|
||||
import ca.uhn.fhir.rest.param.*;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class OperationClientR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(OperationClientR4Test.class);
|
||||
private FhirContext ourCtx;
|
||||
private HttpClient ourHttpClient;
|
||||
|
||||
private HttpResponse ourHttpResponse;
|
||||
private IOpClient ourAnnClient;
|
||||
private ArgumentCaptor<HttpUriRequest> capt;
|
||||
private IGenericClient ourGenClient;
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
ourCtx = FhirContext.forR4();
|
||||
|
||||
ourHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
|
||||
ourCtx.getRestfulClientFactory().setHttpClient(ourHttpClient);
|
||||
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
|
||||
ourHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
|
||||
|
||||
Parameters outParams = new Parameters();
|
||||
outParams.addParameter().setName("FOO");
|
||||
final String retVal = ourCtx.newXmlParser().encodeResourceToString(outParams);
|
||||
|
||||
capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(ourHttpClient.execute(capt.capture())).thenReturn(ourHttpResponse);
|
||||
when(ourHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(ourHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(ourHttpResponse.getEntity().getContent()).thenAnswer(new Answer<InputStream>() {
|
||||
@Override
|
||||
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
return new ReaderInputStream(new StringReader(retVal), Charset.forName("UTF-8"));
|
||||
}
|
||||
});
|
||||
|
||||
ourAnnClient = ourCtx.newRestfulClient(IOpClient.class, "http://foo");
|
||||
ourGenClient = ourCtx.newRestfulGenericClient("http://foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonRepeatingGenericUsingParameters() throws Exception {
|
||||
ourGenClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("nonrepeating")
|
||||
.withSearchParameter(Parameters.class, "valstr", new StringParam("str"))
|
||||
.andSearchParameter("valtok", new TokenParam("sys2", "val2"))
|
||||
.execute();
|
||||
Parameters response = ourAnnClient.nonrepeating(new StringParam("str"), new TokenParam("sys", "val"));
|
||||
assertEquals("FOO", response.getParameter().get(0).getName());
|
||||
|
||||
HttpPost value = (HttpPost) capt.getAllValues().get(0);
|
||||
String requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent(), Charsets.UTF_8);
|
||||
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
|
||||
ourLog.info(requestBody);
|
||||
Parameters request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
|
||||
assertEquals("http://foo/$nonrepeating", value.getURI().toASCIIString());
|
||||
assertEquals(2, request.getParameter().size());
|
||||
assertEquals("valstr", request.getParameter().get(0).getName());
|
||||
assertEquals("str", ((StringType) request.getParameter().get(0).getValue()).getValue());
|
||||
assertEquals("valtok", request.getParameter().get(1).getName());
|
||||
assertEquals("sys2|val2", ((StringType) request.getParameter().get(1).getValue()).getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonRepeatingGenericUsingUrl() throws Exception {
|
||||
ourGenClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("nonrepeating")
|
||||
.withSearchParameter(Parameters.class, "valstr", new StringParam("str"))
|
||||
.andSearchParameter("valtok", new TokenParam("sys2", "val2"))
|
||||
.useHttpGet()
|
||||
.execute();
|
||||
Parameters response = ourAnnClient.nonrepeating(new StringParam("str"), new TokenParam("sys", "val"));
|
||||
assertEquals("FOO", response.getParameter().get(0).getName());
|
||||
|
||||
HttpGet value = (HttpGet) capt.getAllValues().get(0);
|
||||
assertEquals("http://foo/$nonrepeating?valstr=str&valtok=sys2%7Cval2", value.getURI().toASCIIString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonRepeatingUsingParameters() throws Exception {
|
||||
Parameters response = ourAnnClient.nonrepeating(new StringParam("str"), new TokenParam("sys", "val"));
|
||||
assertEquals("FOO", response.getParameter().get(0).getName());
|
||||
|
||||
HttpPost value = (HttpPost) capt.getAllValues().get(0);
|
||||
String requestBody = IOUtils.toString(((HttpPost) value).getEntity().getContent(), Charsets.UTF_8);
|
||||
IOUtils.closeQuietly(((HttpPost) value).getEntity().getContent());
|
||||
ourLog.info(requestBody);
|
||||
Parameters request = ourCtx.newXmlParser().parseResource(Parameters.class, requestBody);
|
||||
assertEquals("http://foo/$nonrepeating", value.getURI().toASCIIString());
|
||||
assertEquals(2, request.getParameter().size());
|
||||
assertEquals("valstr", request.getParameter().get(0).getName());
|
||||
assertEquals("str", ((StringType) request.getParameter().get(0).getValue()).getValue());
|
||||
assertEquals("valtok", request.getParameter().get(1).getName());
|
||||
assertEquals("sys|val", ((StringType) request.getParameter().get(1).getValue()).getValue());
|
||||
}
|
||||
|
||||
public interface IOpClient extends IBasicClient {
|
||||
|
||||
@Operation(name = "$andlist", idempotent = true)
|
||||
public Parameters andlist(
|
||||
//@formatter:off
|
||||
@OperationParam(name="valstr", max=10) StringAndListParam theValStr,
|
||||
@OperationParam(name="valtok", max=10) TokenAndListParam theValTok
|
||||
//@formatter:on
|
||||
);
|
||||
|
||||
@Operation(name = "$andlist-withnomax", idempotent = true)
|
||||
public Parameters andlistWithNoMax(
|
||||
//@formatter:off
|
||||
@OperationParam(name="valstr") StringAndListParam theValStr,
|
||||
@OperationParam(name="valtok") TokenAndListParam theValTok
|
||||
//@formatter:on
|
||||
);
|
||||
|
||||
@Operation(name = "$nonrepeating", idempotent = true)
|
||||
public Parameters nonrepeating(
|
||||
//@formatter:off
|
||||
@OperationParam(name="valstr") StringParam theValStr,
|
||||
@OperationParam(name="valtok") TokenParam theValTok
|
||||
//@formatter:on
|
||||
);
|
||||
|
||||
@Operation(name = "$orlist", idempotent = true)
|
||||
public Parameters orlist(
|
||||
//@formatter:off
|
||||
@OperationParam(name="valstr", max=10) List<StringOrListParam> theValStr,
|
||||
@OperationParam(name="valtok", max=10) List<TokenOrListParam> theValTok
|
||||
//@formatter:on
|
||||
);
|
||||
|
||||
@Operation(name = "$orlist-withnomax", idempotent = true)
|
||||
public Parameters orlistWithNoMax(
|
||||
//@formatter:off
|
||||
@OperationParam(name="valstr") List<StringOrListParam> theValStr,
|
||||
@OperationParam(name="valtok") List<TokenOrListParam> theValTok
|
||||
//@formatter:on
|
||||
);
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
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.ClientProtocolException;
|
||||
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.r4.model.*;
|
||||
import org.junit.*;
|
||||
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.*;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.PatchTypeEnum;
|
||||
import ca.uhn.fhir.rest.client.api.*;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class PatchClientR4Test {
|
||||
public interface IClientType extends IRestfulClient {
|
||||
|
||||
@Patch(type=Patient.class)
|
||||
MethodOutcome patch(@IdParam IdType theId, @ResourceParam String theBody, PatchTypeEnum thePatchType);
|
||||
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJsonPatchAnnotation() throws Exception {
|
||||
ArgumentCaptor<HttpUriRequest> capt = prepareResponse();
|
||||
|
||||
IClientType client = ourCtx.newRestfulClient(IClientType.class, "http://example.com/fhir");
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.getText().setDivAsString("A PATIENT");
|
||||
|
||||
MethodOutcome outcome = client.patch(new IdType("Patient/123"), "{}", PatchTypeEnum.JSON_PATCH);
|
||||
|
||||
assertEquals("PATCH", capt.getAllValues().get(0).getMethod());
|
||||
assertEquals("http://example.com/fhir/Patient/123", capt.getAllValues().get(0).getURI().toASCIIString());
|
||||
assertEquals(Constants.CT_JSON_PATCH, capt.getAllValues().get(0).getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
||||
assertEquals("{}", extractBodyAsString(capt));
|
||||
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">OK</div>", ((OperationOutcome) outcome.getOperationOutcome()).getText().getDivAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testJsonPatchFluent() throws Exception {
|
||||
ArgumentCaptor<HttpUriRequest> capt = prepareResponse();
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.getText().setDivAsString("A PATIENT");
|
||||
|
||||
// MethodOutcome outcome = client.patch().resource("").
|
||||
|
||||
// patch(new IdType("Patient/123"), "{}", PatchTypeEnum.JSON_PATCH);
|
||||
|
||||
// assertEquals("PATCH", capt.getAllValues().get(0).getMethod());
|
||||
// assertEquals("http://example.com/fhir/Patient/123", capt.getAllValues().get(0).getURI().toASCIIString());
|
||||
// assertEquals(Constants.CT_JSON_PATCH, capt.getAllValues().get(0).getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
||||
// assertEquals("{}", extractBodyAsString(capt));
|
||||
// assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">OK</div>", ((OperationOutcome) outcome.getOperationOutcome()).getText().getDivAsString());
|
||||
}
|
||||
|
||||
|
||||
private String extractBodyAsString(ArgumentCaptor<HttpUriRequest> capt) throws IOException {
|
||||
String body = IOUtils.toString(((HttpEntityEnclosingRequestBase) capt.getAllValues().get(0)).getEntity().getContent(), "UTF-8");
|
||||
return body;
|
||||
}
|
||||
|
||||
private ArgumentCaptor<HttpUriRequest> prepareResponse() throws IOException, ClientProtocolException {
|
||||
final IParser p = ourCtx.newXmlParser();
|
||||
|
||||
final OperationOutcome resp1 = new OperationOutcome();
|
||||
resp1.getText().setDivAsString("OK");
|
||||
|
||||
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_NEW + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
|
||||
@Override
|
||||
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
return new ReaderInputStream(new StringReader(p.encodeResourceToString(resp1)), Charset.forName("UTF-8"));
|
||||
}
|
||||
});
|
||||
return capt;
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
ourCtx = FhirContext.forR4();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,234 @@
|
||||
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.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.*;
|
||||
|
||||
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.HttpGet;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.message.BasicStatusLine;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
|
||||
import org.junit.*;
|
||||
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.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.annotation.Count;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.SortOrderEnum;
|
||||
import ca.uhn.fhir.rest.api.SortSpec;
|
||||
import ca.uhn.fhir.rest.client.api.IRestfulClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
|
||||
public class SearchClientR4Test {
|
||||
|
||||
private FhirContext ourCtx;
|
||||
private HttpClient ourHttpClient;
|
||||
private HttpResponse ourHttpResponse;
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourCtx = FhirContext.forR4();
|
||||
|
||||
ourHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
|
||||
ourCtx.getRestfulClientFactory().setHttpClient(ourHttpClient);
|
||||
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
|
||||
ourHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
|
||||
}
|
||||
|
||||
/**
|
||||
* See #299
|
||||
*/
|
||||
@Test
|
||||
public void testListResponseWithSearchExtension() throws Exception {
|
||||
|
||||
final String response = createBundleWithSearchExtension();
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(ourHttpClient.execute(capt.capture())).thenReturn(ourHttpResponse);
|
||||
when(ourHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(ourHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(ourHttpResponse.getEntity().getContent()).thenAnswer(new Answer<InputStream>() {
|
||||
@Override
|
||||
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
return new ReaderInputStream(new StringReader(response), Charset.forName("UTF-8"));
|
||||
}
|
||||
});
|
||||
|
||||
ILocationClient client = ourCtx.newRestfulClient(ILocationClient.class, "http://localhost:8081/hapi-fhir/fhir");
|
||||
|
||||
List<Location> matches = client.getMatches(new StringParam("smith"), 100);
|
||||
assertEquals(1, matches.size());
|
||||
assertEquals("Sample Clinic", matches.get(0).getName());
|
||||
|
||||
HttpGet value = (HttpGet) capt.getValue();
|
||||
assertEquals("http://localhost:8081/hapi-fhir/fhir/Location?_query=match&name=smith&_count=100", value.getURI().toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* See #371
|
||||
*/
|
||||
@Test
|
||||
public void testSortForDstu3() throws Exception {
|
||||
|
||||
final String response = createBundleWithSearchExtension();
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(ourHttpClient.execute(capt.capture())).thenReturn(ourHttpResponse);
|
||||
when(ourHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(ourHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(ourHttpResponse.getEntity().getContent()).thenAnswer(new Answer<InputStream>() {
|
||||
@Override
|
||||
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
return new ReaderInputStream(new StringReader(response), Charset.forName("UTF-8"));
|
||||
}
|
||||
});
|
||||
|
||||
ILocationClient client = ourCtx.newRestfulClient(ILocationClient.class, "http://localhost/fhir");
|
||||
|
||||
int idx = 0;
|
||||
|
||||
client.search(new SortSpec("param1", SortOrderEnum.ASC));
|
||||
assertEquals("http://localhost/fhir/Bundle?_sort=param1", ((HttpGet) capt.getAllValues().get(idx++)).getURI().toString());
|
||||
|
||||
client.search(new SortSpec("param1", SortOrderEnum.ASC).setChain(new SortSpec("param2", SortOrderEnum.DESC)));
|
||||
assertEquals("http://localhost/fhir/Bundle?_sort=param1%2C-param2", ((HttpGet) capt.getAllValues().get(idx++)).getURI().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithPrimitiveTypes() throws Exception {
|
||||
TimeZone tz = TimeZone.getDefault();
|
||||
try {
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("America/Toronto"));
|
||||
|
||||
Date date = new Date(23898235986L);
|
||||
Calendar cal = new GregorianCalendar();
|
||||
cal.setTime(date);
|
||||
;
|
||||
|
||||
final String response = createBundleWithSearchExtension();
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(ourHttpClient.execute(capt.capture())).thenReturn(ourHttpResponse);
|
||||
when(ourHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(ourHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(ourHttpResponse.getEntity().getContent()).thenAnswer(new Answer<InputStream>() {
|
||||
@Override
|
||||
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
return new ReaderInputStream(new StringReader(response), Charset.forName("UTF-8"));
|
||||
}
|
||||
});
|
||||
|
||||
ILocationClient client = ourCtx.newRestfulClient(ILocationClient.class, "http://localhost/fhir");
|
||||
|
||||
int idx = 0;
|
||||
|
||||
client.search("STRING1", new StringType("STRING2"), date, cal);
|
||||
assertEquals("http://localhost/fhir/Bundle?stringParam=STRING1&stringTypeParam=STRING2&dateParam=1970-10-04T10:23:55.986-04:00&calParam=1970-10-04T10:23:55.986-04:00",
|
||||
UrlUtil.unescape(((HttpGet) capt.getAllValues().get(idx++)).getURI().toString()));
|
||||
|
||||
client.search(null, null, null, null);
|
||||
assertEquals("http://localhost/fhir/Bundle",
|
||||
UrlUtil.unescape(((HttpGet) capt.getAllValues().get(idx++)).getURI().toString()));
|
||||
} finally {
|
||||
TimeZone.setDefault(tz);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See #299
|
||||
*/
|
||||
@Test
|
||||
public void testBundleResponseWithSearchExtension() throws Exception {
|
||||
|
||||
final String response = createBundleWithSearchExtension();
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(ourHttpClient.execute(capt.capture())).thenReturn(ourHttpResponse);
|
||||
when(ourHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(ourHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(ourHttpResponse.getEntity().getContent()).thenAnswer(new Answer<InputStream>() {
|
||||
@Override
|
||||
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
return new ReaderInputStream(new StringReader(response), Charset.forName("UTF-8"));
|
||||
}
|
||||
});
|
||||
|
||||
ILocationClient client = ourCtx.newRestfulClient(ILocationClient.class, "http://localhost:8081/hapi-fhir/fhir");
|
||||
|
||||
Bundle matches = client.getMatchesReturnBundle(new StringParam("smith"), 100);
|
||||
|
||||
assertEquals(1, matches.getEntry().size());
|
||||
BundleEntryComponent entry = matches.getEntry().get(0);
|
||||
assertEquals("Sample Clinic", ((Location) entry.getResource()).getName());
|
||||
|
||||
List<Extension> ext = entry.getSearch().getExtensionsByUrl("http://hl7.org/fhir/StructureDefinition/algorithmic-match");
|
||||
assertEquals(1, ext.size());
|
||||
|
||||
HttpGet value = (HttpGet) capt.getValue();
|
||||
assertEquals("http://localhost:8081/hapi-fhir/fhir/Location?_query=match&name=smith&_count=100", value.getURI().toString());
|
||||
}
|
||||
|
||||
private String createBundleWithSearchExtension() {
|
||||
//@formatter:off
|
||||
final String response = "<Bundle xmlns=\"http://hl7.org/fhir\">"
|
||||
+ "<id value=\"f61f6ddc-95e8-4ef9-a4cd-17c79bbb74f3\"></id>"
|
||||
+ "<meta><lastUpdated value=\"2016-02-19T12:04:02.616-05:00\"></lastUpdated></meta>"
|
||||
+ "<type value=\"searchset\"></type>"
|
||||
+ "<link><relation value=\"self\"></relation><url value=\"http://localhost:8081/hapi-fhir/fhir/Location?name=Sample+Clinic&_query=match\"></url></link>"
|
||||
+ "<entry>"
|
||||
+ "<resource>"
|
||||
+ "<Location xmlns=\"http://hl7.org/fhir\">"
|
||||
+ "<id value=\"1\"></id>"
|
||||
+ "<name value=\"Sample Clinic\"></name>"
|
||||
+ "</Location>"
|
||||
+ "</resource>"
|
||||
+ "<search>"
|
||||
+ "<extension url=\"http://hl7.org/fhir/StructureDefinition/algorithmic-match\">"
|
||||
+ "<valueCode value=\"probable\"></valueCode>"
|
||||
+ "</extension>"
|
||||
+ "<score value=\"0.8000000000000000444089209850062616169452667236328125\">"
|
||||
+ "</score>"
|
||||
+ "</search>"
|
||||
+ "</entry>"
|
||||
+ "</Bundle>";
|
||||
//@formatter:on
|
||||
return response;
|
||||
}
|
||||
|
||||
public interface ILocationClient extends IRestfulClient {
|
||||
@Search(queryName = "match")
|
||||
public List<Location> getMatches(final @RequiredParam(name = Location.SP_NAME) StringParam name, final @Count Integer count);
|
||||
|
||||
@Search(queryName = "match", type = Location.class)
|
||||
public Bundle getMatchesReturnBundle(final @RequiredParam(name = Location.SP_NAME) StringParam name, final @Count Integer count);
|
||||
|
||||
@Search
|
||||
public Bundle search(@Sort SortSpec theSort);
|
||||
|
||||
@Search
|
||||
public Bundle search(@OptionalParam(name = "stringParam") String theString, @OptionalParam(name = "stringTypeParam") StringType theStringDt, @OptionalParam(name = "dateParam") Date theDate,
|
||||
@OptionalParam(name = "calParam") Calendar theCal);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,168 @@
|
||||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ByteArrayEntity;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.junit.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.annotation.Create;
|
||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class CreateBinaryR4Test {
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static Binary ourLastBinary;
|
||||
private static byte[] ourLastBinaryBytes;
|
||||
private static String ourLastBinaryString;
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourLastBinary = null;
|
||||
ourLastBinaryBytes = null;
|
||||
ourLastBinaryString = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRawBytesBinaryContentType() throws Exception {
|
||||
HttpPost post = new HttpPost("http://localhost:" + ourPort + "/Binary");
|
||||
post.setEntity(new ByteArrayEntity(new byte[] { 0, 1, 2, 3, 4 }));
|
||||
post.addHeader("Content-Type", "application/foo");
|
||||
CloseableHttpResponse status = ourClient.execute(post);
|
||||
try {
|
||||
assertEquals("application/foo", ourLastBinary.getContentType());
|
||||
assertArrayEquals(new byte[] { 0, 1, 2, 3, 4 }, ourLastBinary.getContent());
|
||||
assertArrayEquals(new byte[] { 0, 1, 2, 3, 4 }, ourLastBinaryBytes);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Technically the client shouldn't be doing it this way, but we'll be accepting
|
||||
*/
|
||||
@Test
|
||||
public void testRawBytesFhirContentType() throws Exception {
|
||||
|
||||
Binary b = new Binary();
|
||||
b.setContentType("application/foo");
|
||||
b.setContent(new byte[] { 0, 1, 2, 3, 4 });
|
||||
String encoded = ourCtx.newJsonParser().encodeResourceToString(b);
|
||||
|
||||
HttpPost post = new HttpPost("http://localhost:" + ourPort + "/Binary");
|
||||
post.setEntity(new StringEntity(encoded));
|
||||
post.addHeader("Content-Type", Constants.CT_FHIR_JSON);
|
||||
CloseableHttpResponse status = ourClient.execute(post);
|
||||
try {
|
||||
assertEquals("application/foo", ourLastBinary.getContentType());
|
||||
assertArrayEquals(new byte[] { 0, 1, 2, 3, 4 }, ourLastBinary.getContent());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRawBytesFhirContentTypeContainingFhir() throws Exception {
|
||||
|
||||
Patient p = new Patient();
|
||||
p.getText().setDivAsString("A PATIENT");
|
||||
|
||||
Binary b = new Binary();
|
||||
b.setContentType("application/xml+fhir");
|
||||
b.setContent(ourCtx.newXmlParser().encodeResourceToString(p).getBytes("UTF-8"));
|
||||
String encoded = ourCtx.newJsonParser().encodeResourceToString(b);
|
||||
|
||||
HttpPost post = new HttpPost("http://localhost:" + ourPort + "/Binary");
|
||||
post.setEntity(new StringEntity(encoded));
|
||||
post.addHeader("Content-Type", Constants.CT_FHIR_JSON);
|
||||
CloseableHttpResponse status = ourClient.execute(post);
|
||||
try {
|
||||
assertEquals("application/xml+fhir", ourLastBinary.getContentType());
|
||||
assertArrayEquals(b.getContent(), ourLastBinary.getContent());
|
||||
assertEquals(encoded, ourLastBinaryString);
|
||||
assertArrayEquals(encoded.getBytes("UTF-8"), ourLastBinaryBytes);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRawBytesNoContentType() throws Exception {
|
||||
HttpPost post = new HttpPost("http://localhost:" + ourPort + "/Binary");
|
||||
post.setEntity(new ByteArrayEntity(new byte[] { 0, 1, 2, 3, 4 }));
|
||||
CloseableHttpResponse status = ourClient.execute(post);
|
||||
try {
|
||||
assertNull(ourLastBinary.getContentType());
|
||||
assertArrayEquals(new byte[] { 0, 1, 2, 3, 4 }, ourLastBinary.getContent());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status);
|
||||
}
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourServer.stop();
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourPort = PortUtil.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
BinaryProvider binaryProvider = new BinaryProvider();
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||
servlet.setResourceProviders(binaryProvider);
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
}
|
||||
|
||||
public static class BinaryProvider implements IResourceProvider {
|
||||
|
||||
@Create()
|
||||
public MethodOutcome createBinary(@ResourceParam Binary theBinary, @ResourceParam String theBinaryString, @ResourceParam byte[] theBinaryBytes) {
|
||||
ourLastBinary = theBinary;
|
||||
ourLastBinaryString = theBinaryString;
|
||||
ourLastBinaryBytes = theBinaryBytes;
|
||||
return new MethodOutcome(new IdType("Binary/001/_history/002"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends IBaseResource> getResourceType() {
|
||||
return Binary.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,269 @@
|
||||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.OperationOutcome.OperationOutcomeIssueComponent;
|
||||
import org.junit.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.client.MyPatientWithExtensions;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class CreateR4Test {
|
||||
private static CloseableHttpClient ourClient;
|
||||
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CreateR4Test.class);
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
public static IBaseOperationOutcome ourReturnOo;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourReturnOo = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* #472
|
||||
*/
|
||||
@Test
|
||||
public void testCreateReturnsLocationHeader() throws Exception {
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
|
||||
httpPost.setEntity(new StringEntity("{\"resourceType\":\"Patient\", \"status\":\"active\"}", ContentType.parse("application/fhir+json; charset=utf-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(201, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertEquals(1, status.getHeaders("Location").length);
|
||||
assertEquals(0, status.getHeaders("Content-Location").length);
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/1", status.getFirstHeader("Location").getValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateReturnsOperationOutcome() throws Exception {
|
||||
ourReturnOo = new OperationOutcome().addIssue(new OperationOutcomeIssueComponent().setDiagnostics("DIAG"));
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
|
||||
httpPost.setEntity(new StringEntity("{\"resourceType\":\"Patient\", \"status\":\"active\"}", ContentType.parse("application/fhir+json; charset=utf-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(201, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertThat(responseContent, containsString("DIAG"));
|
||||
}
|
||||
|
||||
/**
|
||||
* #342
|
||||
*/
|
||||
@Test
|
||||
public void testCreateWithInvalidContent() throws Exception {
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
|
||||
httpPost.setEntity(new StringEntity("FOO", ContentType.parse("application/xml+fhir; charset=utf-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertThat(responseContent, containsString("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><issue><severity value=\"error\"/><code value=\"processing\"/><diagnostics value=\""));
|
||||
assertThat(responseContent, containsString("Failed to parse request body as XML resource. Error was: com.ctc.wstx.exc.WstxUnexpectedCharException: Unexpected character 'F'"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithIncorrectContent1() throws Exception {
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
|
||||
httpPost.setEntity(new StringEntity("{\"foo\":\"bar\"}", ContentType.parse("application/xml+fhir; charset=utf-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertThat(responseContent, containsString("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><issue><severity value=\"error\"/><code value=\"processing\"/><diagnostics value=\""));
|
||||
assertThat(responseContent, containsString("Failed to parse request body as XML resource."));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithIncorrectContent2() throws Exception {
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
|
||||
httpPost.setEntity(new StringEntity("{\"foo\":\"bar\"}", ContentType.parse("application/fhir+xml; charset=utf-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertThat(responseContent, containsString("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><issue><severity value=\"error\"/><code value=\"processing\"/><diagnostics value=\""));
|
||||
assertThat(responseContent, containsString("Failed to parse request body as XML resource."));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithIncorrectContent3() throws Exception {
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
|
||||
httpPost.setEntity(new StringEntity("{\"foo\":\"bar\"}", ContentType.parse("application/fhir+json; charset=utf-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertThat(responseContent, containsString("Failed to parse request body as JSON resource."));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearch() throws Exception {
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=xml&_pretty=true");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
//@formatter:off
|
||||
assertThat(responseContent, stringContainsInOrder(
|
||||
"<Patient xmlns=\"http://hl7.org/fhir\">",
|
||||
"<id value=\"0\"/>",
|
||||
"<meta>",
|
||||
"<profile value=\"http://example.com/StructureDefinition/patient_with_extensions\"/>",
|
||||
"</meta>",
|
||||
"<modifierExtension url=\"http://example.com/ext/date\">",
|
||||
"<valueDate value=\"2011-01-01\"/>",
|
||||
"</modifierExtension>",
|
||||
"</Patient>"));
|
||||
//@formatter:on
|
||||
|
||||
assertThat(responseContent, not(containsString("http://hl7.org/fhir/")));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourServer.stop();
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourPort = PortUtil.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
PatientProvider patientProvider = new PatientProvider();
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||
|
||||
servlet.setResourceProviders(patientProvider);
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
|
||||
}
|
||||
|
||||
public static class PatientProvider implements IResourceProvider {
|
||||
|
||||
@Create()
|
||||
public MethodOutcome create(@ResourceParam Patient theIdParam) {
|
||||
return new MethodOutcome(new IdType("Patient", "1"), true).setOperationOutcome(ourReturnOo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Patient> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
@Read()
|
||||
public MyPatientWithExtensions read(@IdParam IdType theIdParam) {
|
||||
MyPatientWithExtensions p0 = new MyPatientWithExtensions();
|
||||
p0.setId(theIdParam);
|
||||
p0.setDateExt(new DateType("2011-01-01"));
|
||||
return p0;
|
||||
}
|
||||
|
||||
@Search
|
||||
public List<IBaseResource> search() {
|
||||
ArrayList<IBaseResource> retVal = new ArrayList<IBaseResource>();
|
||||
|
||||
MyPatientWithExtensions p0 = new MyPatientWithExtensions();
|
||||
p0.setId(new IdType("Patient/0"));
|
||||
p0.setDateExt(new DateType("2011-01-01"));
|
||||
retVal.add(p0);
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.setId(new IdType("Patient/1"));
|
||||
p1.addName().setFamily("The Family");
|
||||
retVal.add(p1);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.junit.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class CustomTypeServerR4 {
|
||||
private static CloseableHttpClient ourClient;
|
||||
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static String ourLastConditionalUrl;
|
||||
private static IdType ourLastId;
|
||||
private static IdType ourLastIdParam;
|
||||
private static boolean ourLastRequestWasSearch;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CustomTypeServerR4.class);
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourLastId = null;
|
||||
ourLastConditionalUrl = null;
|
||||
ourLastIdParam = null;
|
||||
ourLastRequestWasSearch = false;
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreateWithIdInBody() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.setId("2");
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
|
||||
// httpPost.addHeader(Constants.HEADER_IF_NONE_EXIST, "Patient?identifier=system%7C001");
|
||||
httpPost.setEntity(new StringEntity(ourCtx.newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(201, status.getStatusLine().getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithIdInUrl() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/2");
|
||||
// httpPost.addHeader(Constants.HEADER_IF_NONE_EXIST, "Patient?identifier=system%7C001");
|
||||
httpPost.setEntity(new StringEntity(ourCtx.newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
OperationOutcome oo = ourCtx.newXmlParser().parseResource(OperationOutcome.class, responseContent);
|
||||
assertEquals("Can not create resource with ID \"2\", ID must not be supplied on a create (POST) operation (use an HTTP PUT / update operation if you wish to supply an ID)", oo.getIssue().get(0).getDiagnostics());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithIdInUrlForConditional() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/2");
|
||||
httpPost.addHeader(Constants.HEADER_IF_NONE_EXIST, "Patient?identifier=system%7C001");
|
||||
httpPost.setEntity(new StringEntity(ourCtx.newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
OperationOutcome oo = ourCtx.newXmlParser().parseResource(OperationOutcome.class, responseContent);
|
||||
assertEquals("Can not create resource with ID \"2\", ID must not be supplied on a create (POST) operation (use an HTTP PUT / update operation if you wish to supply an ID)", oo.getIssue().get(0).getDiagnostics());
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourServer.stop();
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourPort = PortUtil.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
PatientProvider patientProvider = new PatientProvider();
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||
servlet.setResourceProviders(patientProvider);
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
|
||||
}
|
||||
|
||||
public static class PatientProvider implements IResourceProvider {
|
||||
|
||||
@Create()
|
||||
public MethodOutcome createPatient(@ResourceParam Patient thePatient, @ConditionalUrlParam String theConditional, @IdParam IdType theIdParam) {
|
||||
ourLastConditionalUrl = theConditional;
|
||||
ourLastId = thePatient.getIdElement();
|
||||
ourLastIdParam = theIdParam;
|
||||
return new MethodOutcome(new IdType("Patient/001/_history/002"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Patient> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
@Search
|
||||
public List<IResource> search(@OptionalParam(name = "foo") StringDt theString) {
|
||||
ourLastRequestWasSearch = true;
|
||||
return new ArrayList<IResource>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,230 @@
|
||||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.*;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class DateRangeParamSearchR4Test {
|
||||
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static DateRangeParam ourLastDateRange;
|
||||
private static int ourPort;
|
||||
|
||||
private static Server ourServer;
|
||||
private static SimpleDateFormat ourFmt;
|
||||
private static String ourBaseUrl;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourLastDateRange = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchForMultipleUnqualifiedDate() throws Exception {
|
||||
String baseUrl = "http://localhost:" + ourPort + "/Patient?" + Patient.SP_BIRTHDATE + "=";
|
||||
HttpGet httpGet = new HttpGet(baseUrl + "2012-01-01&" + Patient.SP_BIRTHDATE + "=2012-02-03");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchForOneUnqualifiedDate() throws Exception {
|
||||
HttpGet httpGet = new HttpGet(ourBaseUrl + "?birthdate=2012-01-01");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertEquals("2012-01-01", ourLastDateRange.getLowerBound().getValueAsString());
|
||||
assertEquals("2012-01-01", ourLastDateRange.getUpperBound().getValueAsString());
|
||||
|
||||
assertEquals(parse("2012-01-01 00:00:00.0000"), ourLastDateRange.getLowerBoundAsInstant());
|
||||
assertEquals(parseM1("2012-01-02 00:00:00.0000"), ourLastDateRange.getUpperBoundAsInstant());
|
||||
assertEquals(ParamPrefixEnum.EQUAL, ourLastDateRange.getLowerBound().getPrefix());
|
||||
assertEquals(ParamPrefixEnum.EQUAL, ourLastDateRange.getUpperBound().getPrefix());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchForOneQualifiedDateEq() throws Exception {
|
||||
HttpGet httpGet = new HttpGet(ourBaseUrl + "?birthdate=eq2012-01-01");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertEquals("2012-01-01", ourLastDateRange.getLowerBound().getValueAsString());
|
||||
assertEquals("2012-01-01", ourLastDateRange.getUpperBound().getValueAsString());
|
||||
|
||||
assertEquals(parse("2012-01-01 00:00:00.0000"), ourLastDateRange.getLowerBoundAsInstant());
|
||||
assertEquals(parseM1("2012-01-02 00:00:00.0000"), ourLastDateRange.getUpperBoundAsInstant());
|
||||
assertEquals(ParamPrefixEnum.EQUAL, ourLastDateRange.getLowerBound().getPrefix());
|
||||
assertEquals(ParamPrefixEnum.EQUAL, ourLastDateRange.getUpperBound().getPrefix());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchForOneQualifiedDateGt() throws Exception {
|
||||
HttpGet httpGet = new HttpGet(ourBaseUrl + "?birthdate=gt2012-01-01");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertEquals("2012-01-01", ourLastDateRange.getLowerBound().getValueAsString());
|
||||
assertEquals(null, ourLastDateRange.getUpperBound());
|
||||
|
||||
assertEquals(parse("2012-01-02 00:00:00.0000"), ourLastDateRange.getLowerBoundAsInstant());
|
||||
assertEquals(null, ourLastDateRange.getUpperBoundAsInstant());
|
||||
assertEquals(ParamPrefixEnum.GREATERTHAN, ourLastDateRange.getLowerBound().getPrefix());
|
||||
assertEquals(null, ourLastDateRange.getUpperBound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchForOneQualifiedDateLt() throws Exception {
|
||||
HttpGet httpGet = new HttpGet(ourBaseUrl + "?birthdate=lt2012-01-01");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertEquals(null, ourLastDateRange.getLowerBound());
|
||||
assertEquals("2012-01-01", ourLastDateRange.getUpperBound().getValueAsString());
|
||||
|
||||
assertEquals(null, ourLastDateRange.getLowerBoundAsInstant());
|
||||
assertEquals(parseM1("2012-01-01 00:00:00.0000"), ourLastDateRange.getUpperBoundAsInstant());
|
||||
assertEquals(null, ourLastDateRange.getLowerBound());
|
||||
assertEquals(ParamPrefixEnum.LESSTHAN, ourLastDateRange.getUpperBound().getPrefix());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchForOneQualifiedDateGe() throws Exception {
|
||||
HttpGet httpGet = new HttpGet(ourBaseUrl + "?birthdate=ge2012-01-01");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertEquals("2012-01-01", ourLastDateRange.getLowerBound().getValueAsString());
|
||||
assertEquals(null, ourLastDateRange.getUpperBound());
|
||||
|
||||
assertEquals(parse("2012-01-01 00:00:00.0000"), ourLastDateRange.getLowerBoundAsInstant());
|
||||
assertEquals(null, ourLastDateRange.getUpperBoundAsInstant());
|
||||
assertEquals(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, ourLastDateRange.getLowerBound().getPrefix());
|
||||
assertEquals(null, ourLastDateRange.getUpperBound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchForOneQualifiedDateLe() throws Exception {
|
||||
HttpGet httpGet = new HttpGet(ourBaseUrl + "?birthdate=le2012-01-01");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertEquals(null, ourLastDateRange.getLowerBound());
|
||||
assertEquals("2012-01-01", ourLastDateRange.getUpperBound().getValueAsString());
|
||||
|
||||
assertEquals(null, ourLastDateRange.getLowerBoundAsInstant());
|
||||
assertEquals(parseM1("2012-01-02 00:00:00.0000"), ourLastDateRange.getUpperBoundAsInstant());
|
||||
assertEquals(null, ourLastDateRange.getLowerBound());
|
||||
assertEquals(ParamPrefixEnum.LESSTHAN_OR_EQUALS, ourLastDateRange.getUpperBound().getPrefix());
|
||||
}
|
||||
|
||||
|
||||
public static Date parse(String theString) throws ParseException {
|
||||
return ourFmt.parse(theString);
|
||||
}
|
||||
|
||||
public static Date parseM1(String theString) throws ParseException {
|
||||
return new Date(ourFmt.parse(theString).getTime() - 1L);
|
||||
}
|
||||
static {
|
||||
ourFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSS");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourServer.stop();
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourPort = PortUtil.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||
servlet.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
||||
|
||||
servlet.setResourceProviders(patientProvider);
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
|
||||
ourBaseUrl = "http://localhost:" + ourPort + "/Patient";
|
||||
}
|
||||
|
||||
|
||||
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<Patient> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
|
||||
@Search()
|
||||
public List<Patient> search(@RequiredParam(name=Patient.SP_BIRTHDATE) DateRangeParam theDateRange) {
|
||||
ourLastDateRange = theDateRange;
|
||||
|
||||
ArrayList<Patient> retVal = new ArrayList<Patient>();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.setId("1");
|
||||
patient.addIdentifier().setSystem("system").setValue("hello");
|
||||
retVal.add(patient);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class DeleteConditionalR4Test {
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static IGenericClient ourHapiClient;
|
||||
private static String ourLastConditionalUrl;
|
||||
private static IdType ourLastIdParam;
|
||||
private static boolean ourLastRequestWasDelete;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(DeleteConditionalR4Test.class);
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourLastConditionalUrl = null;
|
||||
ourLastIdParam = null;
|
||||
ourLastRequestWasDelete = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchStillWorks() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
// HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_pretty=true");
|
||||
//
|
||||
// HttpResponse status = ourClient.execute(httpGet);
|
||||
//
|
||||
// String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
// IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
//
|
||||
// ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
//@formatter:off
|
||||
ourHapiClient
|
||||
.delete()
|
||||
.resourceConditionalByType(Patient.class)
|
||||
.where(Patient.IDENTIFIER.exactly().systemAndIdentifier("SOMESYS","SOMEID"))
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
assertTrue(ourLastRequestWasDelete);
|
||||
assertEquals(null, ourLastIdParam);
|
||||
assertEquals("Patient?identifier=SOMESYS%7CSOMEID", ourLastConditionalUrl);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourServer.stop();
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourPort = PortUtil.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
PatientProvider patientProvider = new PatientProvider();
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||
servlet.setResourceProviders(patientProvider);
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
|
||||
ourCtx.getRestfulClientFactory().setSocketTimeout(500 * 1000);
|
||||
ourHapiClient = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/");
|
||||
ourHapiClient.registerInterceptor(new LoggingInterceptor());
|
||||
}
|
||||
|
||||
public static class PatientProvider implements IResourceProvider {
|
||||
|
||||
@Delete()
|
||||
public MethodOutcome deletePatient(@IdParam IdType theIdParam, @ConditionalUrlParam String theConditional) {
|
||||
ourLastRequestWasDelete = true;
|
||||
ourLastConditionalUrl = theConditional;
|
||||
ourLastIdParam = theIdParam;
|
||||
return new MethodOutcome(new IdType("Patient/001/_history/002"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends IBaseResource> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,768 @@
|
||||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.hamcrest.Matchers.containsInRelativeOrder;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.*;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestOperationComponent;
|
||||
import org.hl7.fhir.r4.model.OperationDefinition.OperationParameterUse;
|
||||
import org.junit.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class OperationServerR4Test {
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static FhirContext ourCtx;
|
||||
|
||||
private static IdType ourLastId;
|
||||
private static String ourLastMethod;
|
||||
private static StringType ourLastParam1;
|
||||
private static Patient ourLastParam2;
|
||||
private static List<StringType> ourLastParam3;
|
||||
private static Money ourLastParamMoney1;
|
||||
private static UnsignedIntType ourLastParamUnsignedInt1;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(OperationServerR4Test.class);
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private IGenericClient myFhirClient;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourLastParam1 = null;
|
||||
ourLastParam2 = null;
|
||||
ourLastParam3 = null;
|
||||
ourLastParamUnsignedInt1 = null;
|
||||
ourLastParamMoney1 = null;
|
||||
ourLastId = null;
|
||||
ourLastMethod = "";
|
||||
|
||||
myFhirClient = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testConformance() throws Exception {
|
||||
LoggingInterceptor loggingInterceptor = new LoggingInterceptor();
|
||||
loggingInterceptor.setLogResponseBody(true);
|
||||
myFhirClient.registerInterceptor(loggingInterceptor);
|
||||
|
||||
CapabilityStatement p = myFhirClient.fetchConformance().ofType(CapabilityStatement.class).prettyPrint().execute();
|
||||
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p));
|
||||
|
||||
List<CapabilityStatementRestOperationComponent> ops = p.getRest().get(0).getOperation();
|
||||
assertThat(ops.size(), greaterThan(1));
|
||||
|
||||
List<String> opNames = toOpNames(ops);
|
||||
assertThat(opNames, containsInRelativeOrder("OP_TYPE"));
|
||||
|
||||
// OperationDefinition def = (OperationDefinition) ops.get(opNames.indexOf("OP_TYPE")).getDefinition().getResource();
|
||||
OperationDefinition def = myFhirClient.read().resource(OperationDefinition.class).withId(ops.get(opNames.indexOf("OP_TYPE")).getDefinition().getReferenceElement()).execute();
|
||||
assertEquals("OP_TYPE", def.getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* See #380
|
||||
*/
|
||||
@Test
|
||||
public void testOperationDefinition() {
|
||||
OperationDefinition def = myFhirClient.read().resource(OperationDefinition.class).withId("OperationDefinition/Patient--OP_TYPE").execute();
|
||||
|
||||
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(def));
|
||||
|
||||
// @OperationParam(name="PARAM1") StringType theParam1,
|
||||
// @OperationParam(name="PARAM2") Patient theParam2,
|
||||
// @OperationParam(name="PARAM3", min=2, max=5) List<StringType> theParam3,
|
||||
// @OperationParam(name="PARAM4", min=1) List<StringType> theParam4,
|
||||
|
||||
assertEquals(4, def.getParameter().size());
|
||||
assertEquals("PARAM1", def.getParameter().get(0).getName());
|
||||
assertEquals(OperationParameterUse.IN, def.getParameter().get(0).getUse());
|
||||
assertEquals(0, def.getParameter().get(0).getMin());
|
||||
assertEquals("1", def.getParameter().get(0).getMax());
|
||||
|
||||
assertEquals("PARAM2", def.getParameter().get(1).getName());
|
||||
assertEquals(OperationParameterUse.IN, def.getParameter().get(1).getUse());
|
||||
assertEquals(0, def.getParameter().get(1).getMin());
|
||||
assertEquals("1", def.getParameter().get(1).getMax());
|
||||
|
||||
assertEquals("PARAM3", def.getParameter().get(2).getName());
|
||||
assertEquals(OperationParameterUse.IN, def.getParameter().get(2).getUse());
|
||||
assertEquals(2, def.getParameter().get(2).getMin());
|
||||
assertEquals("5", def.getParameter().get(2).getMax());
|
||||
|
||||
assertEquals("PARAM4", def.getParameter().get(3).getName());
|
||||
assertEquals(OperationParameterUse.IN, def.getParameter().get(3).getUse());
|
||||
assertEquals(1, def.getParameter().get(3).getMin());
|
||||
assertEquals("*", def.getParameter().get(3).getMax());
|
||||
|
||||
}
|
||||
|
||||
private List<String> toOpNames(List<CapabilityStatementRestOperationComponent> theOps) {
|
||||
ArrayList<String> retVal = new ArrayList<String>();
|
||||
for (CapabilityStatementRestOperationComponent next : theOps) {
|
||||
retVal.add(next.getName());
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstanceEverythingGet() throws Exception {
|
||||
|
||||
// Try with a GET
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$everything");
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("instance $everything", ourLastMethod);
|
||||
assertThat(response, startsWith("<Bundle"));
|
||||
assertEquals("Patient/123", ourLastId.toUnqualifiedVersionless().getValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstanceEverythingHapiClient() throws Exception {
|
||||
ourCtx.newRestfulGenericClient("http://localhost:" + ourPort).operation().onInstance(new IdType("Patient/123")).named("$everything").withParameters(new Parameters()).execute();
|
||||
|
||||
assertEquals("instance $everything", ourLastMethod);
|
||||
assertEquals("Patient/123", ourLastId.toUnqualifiedVersionless().getValue());
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstanceEverythingPost() throws Exception {
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(new Parameters());
|
||||
|
||||
// Try with a POST
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/123/$everything");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("instance $everything", ourLastMethod);
|
||||
assertThat(response, startsWith("<Bundle"));
|
||||
assertEquals("Patient/123", ourLastId.toUnqualifiedVersionless().getValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationCantUseGetIfItIsntIdempotent() throws Exception {
|
||||
HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$OP_INSTANCE");
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(Constants.STATUS_HTTP_405_METHOD_NOT_ALLOWED, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("POST", status.getFirstHeader(Constants.HEADER_ALLOW).getValue());
|
||||
assertThat(response, containsString("HTTP Method GET is not allowed"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationWrongParameterType() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("PARAM1").setValue(new IntegerType(123));
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/123/$OP_INSTANCE");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
CloseableHttpResponse status = ourClient.execute(httpPost);
|
||||
try {
|
||||
String response = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
assertThat(response, containsString("Request has parameter PARAM1 of type IntegerType but method expects type StringType"));
|
||||
ourLog.info(response);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationOnInstance() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("PARAM1").setValue(new StringType("PARAM1val"));
|
||||
p.addParameter().setName("PARAM2").setResource(new Patient().setActive(true));
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/123/$OP_INSTANCE");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("PARAM1val", ourLastParam1.getValue());
|
||||
assertEquals(true, ourLastParam2.getActive());
|
||||
assertEquals("123", ourLastId.getIdPart());
|
||||
assertEquals("$OP_INSTANCE", ourLastMethod);
|
||||
|
||||
Parameters resp = ourCtx.newXmlParser().parseResource(Parameters.class, response);
|
||||
assertEquals("RET1", resp.getParameter().get(0).getName());
|
||||
|
||||
/*
|
||||
* Against type should fail
|
||||
*/
|
||||
|
||||
httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$OP_INSTANCE");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
status = ourClient.execute(httpPost);
|
||||
|
||||
response = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(response);
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationOnInstanceAndType_Instance() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("PARAM1").setValue(new StringType("PARAM1val"));
|
||||
p.addParameter().setName("PARAM2").setResource(new Patient().setActive(true));
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/123/$OP_INSTANCE_OR_TYPE");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("PARAM1val", ourLastParam1.getValue());
|
||||
assertEquals(true, ourLastParam2.getActive());
|
||||
assertEquals("123", ourLastId.getIdPart());
|
||||
assertEquals("$OP_INSTANCE_OR_TYPE", ourLastMethod);
|
||||
|
||||
Parameters resp = ourCtx.newXmlParser().parseResource(Parameters.class, response);
|
||||
assertEquals("RET1", resp.getParameter().get(0).getName());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationOnInstanceAndType_Type() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("PARAM1").setValue(new StringType("PARAM1val"));
|
||||
p.addParameter().setName("PARAM2").setResource(new Patient().setActive(true));
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$OP_INSTANCE_OR_TYPE");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
CloseableHttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("PARAM1val", ourLastParam1.getValue());
|
||||
assertEquals(true, ourLastParam2.getActive());
|
||||
assertEquals(null, ourLastId);
|
||||
assertEquals("$OP_INSTANCE_OR_TYPE", ourLastMethod);
|
||||
|
||||
Parameters resp = ourCtx.newXmlParser().parseResource(Parameters.class, response);
|
||||
assertEquals("RET1", resp.getParameter().get(0).getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationOnServer() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("PARAM1").setValue(new StringType("PARAM1val"));
|
||||
p.addParameter().setName("PARAM2").setResource(new Patient().setActive(true));
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/$OP_SERVER");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("PARAM1val", ourLastParam1.getValue());
|
||||
assertEquals(true, ourLastParam2.getActive());
|
||||
assertEquals("$OP_SERVER", ourLastMethod);
|
||||
|
||||
Parameters resp = ourCtx.newXmlParser().parseResource(Parameters.class, response);
|
||||
assertEquals("RET1", resp.getParameter().get(0).getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationOnType() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("PARAM1").setValue(new StringType("PARAM1val"));
|
||||
p.addParameter().setName("PARAM2").setResource(new Patient().setActive(true));
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$OP_TYPE");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("PARAM1val", ourLastParam1.getValue());
|
||||
assertEquals(true, ourLastParam2.getActive());
|
||||
assertEquals("$OP_TYPE", ourLastMethod);
|
||||
|
||||
Parameters resp = ourCtx.newXmlParser().parseResource(Parameters.class, response);
|
||||
assertEquals("RET1", resp.getParameter().get(0).getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationOnTypeReturnBundle() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("PARAM1").setValue(new StringType("PARAM1val"));
|
||||
p.addParameter().setName("PARAM2").setResource(new Patient().setActive(true));
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$OP_TYPE_RET_BUNDLE");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("PARAM1val", ourLastParam1.getValue());
|
||||
assertEquals(true, ourLastParam2.getActive());
|
||||
assertEquals("$OP_TYPE_RET_BUNDLE", ourLastMethod);
|
||||
|
||||
Bundle resp = ourCtx.newXmlParser().parseResource(Bundle.class, response);
|
||||
assertEquals("100", resp.getEntryFirstRep().getResponse().getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationWithBundleProviderResponse() throws Exception {
|
||||
HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/$OP_INSTANCE_BUNDLE_PROVIDER?_pretty=true");
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(response);
|
||||
|
||||
ourCtx.newXmlParser().parseResource(Bundle.class, response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationWithGetUsingParams() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$OP_TYPE?PARAM1=PARAM1val");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("PARAM1val", ourLastParam1.getValue());
|
||||
assertNull(ourLastParam2);
|
||||
assertEquals("$OP_TYPE", ourLastMethod);
|
||||
|
||||
Parameters resp = ourCtx.newXmlParser().parseResource(Parameters.class, response);
|
||||
assertEquals("RET1", resp.getParameter().get(0).getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationWithGetUsingParamsFailsWithNonPrimitive() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$OP_TYPE?PARAM1=PARAM1val&PARAM2=foo");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
assertEquals(405, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("POST", status.getFirstHeader(Constants.HEADER_ALLOW).getValue());
|
||||
assertThat(response, containsString("Can not invoke operation $OP_TYPE using HTTP GET because parameter PARAM2 is not a primitive datatype"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testOperationWithListParam() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("PARAM2").setResource(new Patient().setActive(true));
|
||||
p.addParameter().setName("PARAM3").setValue(new StringType("PARAM3val1"));
|
||||
p.addParameter().setName("PARAM3").setValue(new StringType("PARAM3val2"));
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/$OP_SERVER_LIST_PARAM");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("$OP_SERVER_LIST_PARAM", ourLastMethod);
|
||||
assertEquals(true, ourLastParam2.getActive());
|
||||
assertEquals(null, ourLastParam1);
|
||||
assertEquals(2, ourLastParam3.size());
|
||||
assertEquals("PARAM3val1", ourLastParam3.get(0).getValue());
|
||||
assertEquals("PARAM3val2", ourLastParam3.get(1).getValue());
|
||||
|
||||
Parameters resp = ourCtx.newXmlParser().parseResource(Parameters.class, response);
|
||||
assertEquals("RET1", resp.getParameter().get(0).getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationWithProfileDatatypeParams() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("PARAM1").setValue(new IntegerType("123"));
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$OP_PROFILE_DT");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("$OP_PROFILE_DT", ourLastMethod);
|
||||
assertEquals("123", ourLastParamUnsignedInt1.getValueAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationWithProfileDatatypeParams2() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
Money money = new Money();
|
||||
money.setCode("CODE");
|
||||
money.setSystem("SYSTEM");
|
||||
money.setValue(123L);
|
||||
p.addParameter().setName("PARAM1").setValue(money);
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$OP_PROFILE_DT2");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("$OP_PROFILE_DT2", ourLastMethod);
|
||||
assertEquals("CODE", ourLastParamMoney1.getCode());
|
||||
assertEquals("SYSTEM", ourLastParamMoney1.getSystem());
|
||||
assertEquals("123", ourLastParamMoney1.getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationWithProfileDatatypeUrl() throws Exception {
|
||||
HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient/$OP_PROFILE_DT?PARAM1=123");
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("$OP_PROFILE_DT", ourLastMethod);
|
||||
assertEquals("123", ourLastParamUnsignedInt1.getValueAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationWrongParamType() throws Exception {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("PARAM1").setValue(new IntegerType("123"));
|
||||
p.addParameter().setName("PARAM2").setResource(new Patient().setActive(true));
|
||||
String inParamsStr = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$OP_TYPE");
|
||||
httpPost.setEntity(new StringEntity(inParamsStr, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
String response = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info(status.getStatusLine().toString());
|
||||
ourLog.info(response);
|
||||
|
||||
assertThat(response, containsString("Request has parameter PARAM1 of type IntegerType but method expects type StringType"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadWithOperations() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals("read", ourLastMethod);
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourServer.stop();
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourCtx = FhirContext.forR4();
|
||||
ourPort = PortUtil.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||
|
||||
servlet.setPagingProvider(new FifoMemoryPagingProvider(10).setDefaultPageSize(2));
|
||||
|
||||
servlet.setFhirContext(ourCtx);
|
||||
servlet.setResourceProviders(new PatientProvider());
|
||||
servlet.setPlainProviders(new PlainProvider());
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] theValue) {
|
||||
Parameters p = new Parameters();
|
||||
p.addParameter().setName("start").setValue(new DateTimeType("2001-01-02"));
|
||||
p.addParameter().setName("end").setValue(new DateTimeType("2015-07-10"));
|
||||
String inParamsStr = FhirContext.forDstu2().newXmlParser().encodeResourceToString(p);
|
||||
ourLog.info(inParamsStr.replace("\"", "\\\""));
|
||||
}
|
||||
|
||||
public static class PatientProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<Patient> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name="$OP_INSTANCE")
|
||||
public Parameters opInstance(
|
||||
@IdParam IdType theId,
|
||||
@OperationParam(name="PARAM1") StringType theParam1,
|
||||
@OperationParam(name="PARAM2") Patient theParam2
|
||||
) {
|
||||
//@formatter:on
|
||||
|
||||
ourLastMethod = "$OP_INSTANCE";
|
||||
ourLastId = theId;
|
||||
ourLastParam1 = theParam1;
|
||||
ourLastParam2 = theParam2;
|
||||
|
||||
Parameters retVal = new Parameters();
|
||||
retVal.addParameter().setName("RET1").setValue(new StringType("RETVAL1"));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name="$OP_INSTANCE_OR_TYPE")
|
||||
public Parameters opInstanceOrType(
|
||||
@IdParam(optional=true) IdType theId,
|
||||
@OperationParam(name="PARAM1") StringType theParam1,
|
||||
@OperationParam(name="PARAM2") Patient theParam2
|
||||
) {
|
||||
//@formatter:on
|
||||
|
||||
ourLastMethod = "$OP_INSTANCE_OR_TYPE";
|
||||
ourLastId = theId;
|
||||
ourLastParam1 = theParam1;
|
||||
ourLastParam2 = theParam2;
|
||||
|
||||
Parameters retVal = new Parameters();
|
||||
retVal.addParameter().setName("RET1").setValue(new StringType("RETVAL1"));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name="$OP_PROFILE_DT2", idempotent=true)
|
||||
public Bundle opProfileType(
|
||||
@OperationParam(name="PARAM1") Money theParam1
|
||||
) {
|
||||
//@formatter:on
|
||||
|
||||
ourLastMethod = "$OP_PROFILE_DT2";
|
||||
ourLastParamMoney1 = theParam1;
|
||||
|
||||
Bundle retVal = new Bundle();
|
||||
retVal.addEntry().getResponse().setStatus("100");
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name="$OP_PROFILE_DT", idempotent=true)
|
||||
public Bundle opProfileType(
|
||||
@OperationParam(name="PARAM1") UnsignedIntType theParam1
|
||||
) {
|
||||
//@formatter:on
|
||||
|
||||
ourLastMethod = "$OP_PROFILE_DT";
|
||||
ourLastParamUnsignedInt1 = theParam1;
|
||||
|
||||
Bundle retVal = new Bundle();
|
||||
retVal.addEntry().getResponse().setStatus("100");
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@SuppressWarnings("unused")
|
||||
@Operation(name="$OP_TYPE", idempotent=true)
|
||||
public Parameters opType(
|
||||
@OperationParam(name="PARAM1") StringType theParam1,
|
||||
@OperationParam(name="PARAM2") Patient theParam2,
|
||||
@OperationParam(name="PARAM3", min=2, max=5) List<StringType> theParam3,
|
||||
@OperationParam(name="PARAM4", min=1) List<StringType> theParam4
|
||||
) {
|
||||
//@formatter:on
|
||||
|
||||
ourLastMethod = "$OP_TYPE";
|
||||
ourLastParam1 = theParam1;
|
||||
ourLastParam2 = theParam2;
|
||||
|
||||
Parameters retVal = new Parameters();
|
||||
retVal.addParameter().setName("RET1").setValue(new StringType("RETVAL1"));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name="$OP_TYPE_ONLY_STRING", idempotent=true)
|
||||
public Parameters opTypeOnlyString(
|
||||
@OperationParam(name="PARAM1") StringType theParam1
|
||||
) {
|
||||
//@formatter:on
|
||||
|
||||
ourLastMethod = "$OP_TYPE";
|
||||
ourLastParam1 = theParam1;
|
||||
|
||||
Parameters retVal = new Parameters();
|
||||
retVal.addParameter().setName("RET1").setValue(new StringType("RETVAL1"));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name="$OP_TYPE_RET_BUNDLE")
|
||||
public Bundle opTypeRetBundle(
|
||||
@OperationParam(name="PARAM1") StringType theParam1,
|
||||
@OperationParam(name="PARAM2") Patient theParam2
|
||||
) {
|
||||
//@formatter:on
|
||||
|
||||
ourLastMethod = "$OP_TYPE_RET_BUNDLE";
|
||||
ourLastParam1 = theParam1;
|
||||
ourLastParam2 = theParam2;
|
||||
|
||||
Bundle retVal = new Bundle();
|
||||
retVal.addEntry().getResponse().setStatus("100");
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Operation(name = "$everything", idempotent=true)
|
||||
public Bundle patientEverything(@IdParam IdType thePatientId) {
|
||||
ourLastMethod = "instance $everything";
|
||||
ourLastId = thePatientId;
|
||||
return new Bundle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Just to make sure this method doesn't "steal" calls
|
||||
*/
|
||||
@Read
|
||||
public Patient read(@IdParam IdType theId) {
|
||||
ourLastMethod = "read";
|
||||
Patient retVal = new Patient();
|
||||
retVal.setId(theId);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class PlainProvider {
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name="$OP_INSTANCE_BUNDLE_PROVIDER", idempotent=true)
|
||||
public IBundleProvider opInstanceReturnsBundleProvider() {
|
||||
ourLastMethod = "$OP_INSTANCE_BUNDLE_PROVIDER";
|
||||
|
||||
List<IBaseResource> resources = new ArrayList<IBaseResource>();
|
||||
for (int i =0; i < 100;i++) {
|
||||
Patient p = new Patient();
|
||||
p.setId("Patient/" + i);
|
||||
p.addName().setFamily("Patient " + i);
|
||||
resources.add(p);
|
||||
}
|
||||
|
||||
return new SimpleBundleProvider(resources);
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name="$OP_SERVER")
|
||||
public Parameters opServer(
|
||||
@OperationParam(name="PARAM1") StringType theParam1,
|
||||
@OperationParam(name="PARAM2") Patient theParam2
|
||||
) {
|
||||
//@formatter:on
|
||||
|
||||
ourLastMethod = "$OP_SERVER";
|
||||
ourLastParam1 = theParam1;
|
||||
ourLastParam2 = theParam2;
|
||||
|
||||
Parameters retVal = new Parameters();
|
||||
retVal.addParameter().setName("RET1").setValue(new StringType("RETVAL1"));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name="$OP_SERVER_LIST_PARAM")
|
||||
public Parameters opServerListParam(
|
||||
@OperationParam(name="PARAM2") Patient theParam2,
|
||||
@OperationParam(name="PARAM3") List<StringType> theParam3
|
||||
) {
|
||||
//@formatter:on
|
||||
|
||||
ourLastMethod = "$OP_SERVER_LIST_PARAM";
|
||||
ourLastParam2 = theParam2;
|
||||
ourLastParam3 = theParam3;
|
||||
|
||||
Parameters retVal = new Parameters();
|
||||
retVal.addParameter().setName("RET1").setValue(new StringType("RETVAL1"));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,187 @@
|
||||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleLinkComponent;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.*;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.TokenAndListParam;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class SearchBundleProviderWithNoSizeR4Test {
|
||||
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static TokenAndListParam ourIdentifiers;
|
||||
private static IBundleProvider ourLastBundleProvider;
|
||||
private static String ourLastMethod;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchBundleProviderWithNoSizeR4Test.class);
|
||||
private static int ourPort;
|
||||
|
||||
private static Server ourServer;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourLastMethod = null;
|
||||
ourIdentifiers = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBundleProviderReturnsNoSize() throws Exception {
|
||||
Bundle respBundle;
|
||||
|
||||
ourLastBundleProvider = mock(IBundleProvider.class);
|
||||
when(ourLastBundleProvider.size()).thenReturn(null);
|
||||
when(ourLastBundleProvider.getResources(any(int.class), any(int.class))).then(new Answer<List<IBaseResource>>() {
|
||||
@Override
|
||||
public List<IBaseResource> answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
int from =(Integer)theInvocation.getArguments()[0];
|
||||
int to =(Integer)theInvocation.getArguments()[1];
|
||||
ArrayList<IBaseResource> retVal = Lists.newArrayList();
|
||||
for (int i = from; i < to; i++) {
|
||||
Patient p = new Patient();
|
||||
p.setId(Integer.toString(i));
|
||||
retVal.add(p);
|
||||
}
|
||||
return retVal;
|
||||
}});
|
||||
|
||||
HttpGet httpGet;
|
||||
CloseableHttpResponse status = null;
|
||||
BundleLinkComponent linkNext;
|
||||
|
||||
try {
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=json");
|
||||
status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals("searchAll", ourLastMethod);
|
||||
respBundle = ourCtx.newJsonParser().parseResource(Bundle.class, responseContent);
|
||||
|
||||
assertEquals(10, respBundle.getEntry().size());
|
||||
assertEquals("Patient/0", respBundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||
linkNext = respBundle.getLink("next");
|
||||
assertNotNull(linkNext);
|
||||
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
|
||||
when(ourLastBundleProvider.size()).thenReturn(25);
|
||||
|
||||
try {
|
||||
httpGet = new HttpGet(linkNext.getUrl());
|
||||
status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals("searchAll", ourLastMethod);
|
||||
respBundle = ourCtx.newJsonParser().parseResource(Bundle.class, responseContent);
|
||||
|
||||
assertEquals(10, respBundle.getEntry().size());
|
||||
assertEquals("Patient/10", respBundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||
linkNext = respBundle.getLink("next");
|
||||
assertNotNull(linkNext);
|
||||
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
try {
|
||||
httpGet = new HttpGet(linkNext.getUrl());
|
||||
status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals("searchAll", ourLastMethod);
|
||||
respBundle = ourCtx.newJsonParser().parseResource(Bundle.class, responseContent);
|
||||
|
||||
assertEquals(5, respBundle.getEntry().size());
|
||||
assertEquals("Patient/20", respBundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||
linkNext = respBundle.getLink("next");
|
||||
assertNull(linkNext);
|
||||
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourServer.stop();
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourPort = PortUtil.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||
servlet.setPagingProvider(new FifoMemoryPagingProvider(10));
|
||||
|
||||
servlet.setResourceProviders(patientProvider);
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
|
||||
}
|
||||
|
||||
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<? extends IBaseResource> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
@Search()
|
||||
public IBundleProvider searchAll() {
|
||||
ourLastMethod = "searchAll";
|
||||
return ourLastBundleProvider;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.HumanName;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.*;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.param.*;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class SearchHasParamR4Test {
|
||||
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchHasParamR4Test.class);
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private static String ourLastMethod;
|
||||
private static HasAndListParam ourLastParam;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourLastMethod = null;
|
||||
ourLastParam = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearch() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_has:Encounter:patient:type=SURG");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals("search", ourLastMethod);
|
||||
|
||||
HasParam param = ourLastParam.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0);
|
||||
assertEquals("Encounter", param.getTargetResourceType());
|
||||
assertEquals("patient", param.getOwningFieldName());
|
||||
assertEquals("type", param.getParameterName());
|
||||
assertEquals("SURG", param.getParameterValue());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourServer.stop();
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourPort = PortUtil.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||
servlet.setPagingProvider(new FifoMemoryPagingProvider(10));
|
||||
|
||||
servlet.setResourceProviders(patientProvider);
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
|
||||
}
|
||||
|
||||
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<? extends IBaseResource> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Search()
|
||||
public List search(
|
||||
@OptionalParam(name=Patient.SP_IDENTIFIER) TokenParam theIdentifier,
|
||||
@OptionalParam(name="_has") HasAndListParam theParam
|
||||
) {
|
||||
ourLastMethod = "search";
|
||||
ourLastParam = theParam;
|
||||
ArrayList<Patient> retVal = new ArrayList<Patient>();
|
||||
retVal.add((Patient) new Patient().addName(new HumanName().setFamily("FAMILY")).setId("1"));
|
||||
return retVal;
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,368 @@
|
||||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.junit.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
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.SearchStyleEnum;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.rest.gclient.StringClientParam;
|
||||
import ca.uhn.fhir.rest.param.TokenAndListParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.*;
|
||||
|
||||
public class SearchR4Test {
|
||||
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static TokenAndListParam ourIdentifiers;
|
||||
private static String ourLastMethod;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchR4Test.class);
|
||||
private static int ourPort;
|
||||
|
||||
private static Server ourServer;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourLastMethod = null;
|
||||
ourIdentifiers = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchNormal() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar");
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertEquals("search", ourLastMethod);
|
||||
|
||||
assertEquals("foo", ourIdentifiers.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getSystem());
|
||||
assertEquals("bar", ourIdentifiers.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValue());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithInvalidChain() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier.chain=foo%7Cbar");
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
|
||||
OperationOutcome oo = (OperationOutcome) ourCtx.newJsonParser().parseResource(responseContent);
|
||||
assertEquals(
|
||||
"Invalid search parameter \"identifier.chain\". Parameter contains a chain (.chain) and chains are not supported for this parameter (chaining is only allowed on reference parameters)",
|
||||
oo.getIssueFirstRep().getDiagnostics());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPagingPreservesEncodingJson() throws Exception {
|
||||
HttpGet httpGet;
|
||||
String linkNext;
|
||||
Bundle bundle;
|
||||
|
||||
// Initial search
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_format=json");
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=json"));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=json"));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=json"));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=json"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPagingPreservesEncodingApplicationJsonFhir() throws Exception {
|
||||
HttpGet httpGet;
|
||||
String linkNext;
|
||||
Bundle bundle;
|
||||
|
||||
// Initial search
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_format=" + Constants.CT_FHIR_JSON_NEW);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=" + UrlUtil.escape(Constants.CT_FHIR_JSON_NEW)));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=" + UrlUtil.escape(Constants.CT_FHIR_JSON_NEW)));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=" + UrlUtil.escape(Constants.CT_FHIR_JSON_NEW)));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=" + UrlUtil.escape(Constants.CT_FHIR_JSON_NEW)));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPagingPreservesEncodingXml() throws Exception {
|
||||
HttpGet httpGet;
|
||||
String linkNext;
|
||||
Bundle bundle;
|
||||
|
||||
// Initial search
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_format=xml");
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=xml"));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=xml"));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=xml"));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=xml"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPagingPreservesEncodingNone() throws Exception {
|
||||
HttpGet httpGet;
|
||||
String linkNext;
|
||||
Bundle bundle;
|
||||
|
||||
// Initial search
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar");
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, not(containsString("_format")));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, not(containsString("_format")));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, not(containsString("_format")));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, not(containsString("_format")));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPagingPreservesEncodingNoneWithBrowserAcceptHeader() throws Exception {
|
||||
HttpGet httpGet;
|
||||
String linkNext;
|
||||
Bundle bundle;
|
||||
|
||||
// Initial search
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar");
|
||||
httpGet.addHeader(Constants.HEADER_ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, not(containsString("_format")));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
httpGet.addHeader(Constants.HEADER_ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, not(containsString("_format")));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
httpGet.addHeader(Constants.HEADER_ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, not(containsString("_format")));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
httpGet.addHeader(Constants.HEADER_ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, not(containsString("_format")));
|
||||
|
||||
}
|
||||
|
||||
private Bundle executeAndReturnLinkNext(HttpGet httpGet, EncodingEnum theExpectEncoding) throws IOException, ClientProtocolException {
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
Bundle bundle;
|
||||
try {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
EncodingEnum ct = EncodingEnum.forContentType(status.getEntity().getContentType().getValue().replaceAll(";.*", "").trim());
|
||||
assertEquals(theExpectEncoding, ct);
|
||||
bundle = ct.newParser(ourCtx).parseResource(Bundle.class, responseContent);
|
||||
assertEquals(10, bundle.getEntry().size());
|
||||
String linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertNotNull(linkNext);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchWithPostAndInvalidParameters() throws Exception {
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort);
|
||||
LoggingInterceptor interceptor = new LoggingInterceptor();
|
||||
interceptor.setLogRequestSummary(true);
|
||||
interceptor.setLogRequestBody(true);
|
||||
interceptor.setLogRequestHeaders(false);
|
||||
interceptor.setLogResponseBody(false);
|
||||
interceptor.setLogResponseHeaders(false);
|
||||
interceptor.setLogResponseSummary(false);
|
||||
client.registerInterceptor(interceptor);
|
||||
try {
|
||||
client
|
||||
.search()
|
||||
.forResource(Patient.class)
|
||||
.where(new StringClientParam("foo").matches().value("bar"))
|
||||
.encodedJson()
|
||||
.prettyPrint()
|
||||
.usingStyle(SearchStyleEnum.POST)
|
||||
.returnBundle(org.hl7.fhir.r4.model.Bundle.class)
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertThat(e.getMessage(), containsString("Invalid request: The FHIR endpoint on this server does not know how to handle POST operation[Patient/_search] with parameters [[_pretty, foo]]"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourServer.stop();
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourPort = PortUtil.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||
servlet.setDefaultResponseEncoding(EncodingEnum.JSON);
|
||||
servlet.setPagingProvider(new FifoMemoryPagingProvider(10));
|
||||
|
||||
servlet.setResourceProviders(patientProvider);
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
|
||||
}
|
||||
|
||||
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<? extends IBaseResource> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Search()
|
||||
public List search(
|
||||
@RequiredParam(name = Patient.SP_IDENTIFIER) TokenAndListParam theIdentifiers) {
|
||||
ourLastMethod = "search";
|
||||
ourIdentifiers = theIdentifiers;
|
||||
ArrayList<Patient> retVal = new ArrayList<Patient>();
|
||||
|
||||
for (int i = 0; i < 200; i++) {
|
||||
Patient patient = new Patient();
|
||||
patient.addName(new HumanName().setFamily("FAMILY"));
|
||||
patient.getIdElement().setValue("Patient/" + i);
|
||||
retVal.add((Patient) patient);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.HumanName;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.annotation.Sort;
|
||||
import ca.uhn.fhir.rest.api.SortOrderEnum;
|
||||
import ca.uhn.fhir.rest.api.SortSpec;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class SearchSortR4Test {
|
||||
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchSortR4Test.class);
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private static String ourLastMethod;
|
||||
private static SortSpec ourLastSortSpec;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourLastMethod = null;
|
||||
ourLastSortSpec = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearch() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_sort=param1,-param2,param3,-param4");
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals("search", ourLastMethod);
|
||||
|
||||
assertEquals("param1", ourLastSortSpec.getParamName());
|
||||
assertEquals(SortOrderEnum.ASC, ourLastSortSpec.getOrder());
|
||||
|
||||
assertEquals("param2", ourLastSortSpec.getChain().getParamName());
|
||||
assertEquals(SortOrderEnum.DESC, ourLastSortSpec.getChain().getOrder());
|
||||
|
||||
assertEquals("param3", ourLastSortSpec.getChain().getChain().getParamName());
|
||||
assertEquals(SortOrderEnum.ASC, ourLastSortSpec.getChain().getChain().getOrder());
|
||||
|
||||
assertEquals("param4", ourLastSortSpec.getChain().getChain().getChain().getParamName());
|
||||
assertEquals(SortOrderEnum.DESC, ourLastSortSpec.getChain().getChain().getChain().getOrder());
|
||||
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourServer.stop();
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourPort = PortUtil.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||
servlet.setPagingProvider(new FifoMemoryPagingProvider(10));
|
||||
|
||||
servlet.setResourceProviders(patientProvider);
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
|
||||
}
|
||||
|
||||
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<? extends IBaseResource> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Search()
|
||||
public List search(
|
||||
@Sort SortSpec theSortSpec
|
||||
) {
|
||||
ourLastMethod = "search";
|
||||
ourLastSortSpec = theSortSpec;
|
||||
ArrayList<Patient> retVal = new ArrayList<Patient>();
|
||||
for (int i = 1; i < 100; i++) {
|
||||
retVal.add((Patient) new Patient().addName(new HumanName().setFamily("FAMILY")).setId("" + i));
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,395 @@
|
||||
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.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.*;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.junit.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.client.MyPatientWithExtensions;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class ServerMimetypeR4Test {
|
||||
private static CloseableHttpClient ourClient;
|
||||
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerMimetypeR4Test.class);
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
|
||||
@Test
|
||||
public void testConformanceMetadataUsesNewMimetypes() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/metadata");
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
String content = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
CapabilityStatement conf = ourCtx.newXmlParser().parseResource(CapabilityStatement.class, content);
|
||||
List<String> strings = toStrings(conf.getFormat());
|
||||
assertThat(strings, contains(Constants.CT_FHIR_XML_NEW, Constants.CT_FHIR_JSON_NEW));
|
||||
} finally {
|
||||
status.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private List<String> toStrings(List<CodeType> theFormat) {
|
||||
ArrayList<String> retVal = new ArrayList<String>();
|
||||
for (CodeType next : theFormat) {
|
||||
retVal.add(next.asStringValue());
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreateWithXmlLegacyNoAcceptHeader() throws Exception {
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("FAMILY");
|
||||
String enc = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
|
||||
httpPost.setEntity(new StringEntity(enc, ContentType.parse(Constants.CT_FHIR_XML + "; charset=utf-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(201, status.getStatusLine().getStatusCode());
|
||||
assertEquals(Constants.CT_FHIR_XML, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
||||
assertEquals("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><issue><diagnostics value=\"FAMILY\"/></issue></OperationOutcome>", responseContent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpTraceNotEnabled() throws Exception {
|
||||
HttpTrace req = new HttpTrace("http://localhost:" + ourPort + "/Patient");
|
||||
CloseableHttpResponse status = ourClient.execute(req);
|
||||
try {
|
||||
ourLog.info(status.toString());
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpTrackNotEnabled() throws Exception {
|
||||
HttpRequestBase req = new HttpRequestBase() {
|
||||
@Override
|
||||
public String getMethod() {
|
||||
return "TRACK";
|
||||
}};
|
||||
req.setURI(new URI("http://localhost:" + ourPort + "/Patient"));
|
||||
|
||||
CloseableHttpResponse status = ourClient.execute(req);
|
||||
try {
|
||||
ourLog.info(status.toString());
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithXmlNewNoAcceptHeader() throws Exception {
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("FAMILY");
|
||||
String enc = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
|
||||
httpPost.setEntity(new StringEntity(enc, ContentType.parse(Constants.CT_FHIR_XML_NEW + "; charset=utf-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(201, status.getStatusLine().getStatusCode());
|
||||
assertEquals(Constants.CT_FHIR_XML_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
||||
assertEquals("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><issue><diagnostics value=\"FAMILY\"/></issue></OperationOutcome>", responseContent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithXmlNewWithAcceptHeader() throws Exception {
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("FAMILY");
|
||||
String enc = ourCtx.newXmlParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
|
||||
httpPost.setEntity(new StringEntity(enc, ContentType.parse(Constants.CT_FHIR_XML + "; charset=utf-8")));
|
||||
httpPost.addHeader(Constants.HEADER_ACCEPT, Constants.CT_FHIR_XML_NEW);
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(201, status.getStatusLine().getStatusCode());
|
||||
assertEquals(Constants.CT_FHIR_XML_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
||||
assertEquals("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><issue><diagnostics value=\"FAMILY\"/></issue></OperationOutcome>", responseContent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithJsonLegacyNoAcceptHeader() throws Exception {
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("FAMILY");
|
||||
String enc = ourCtx.newJsonParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
|
||||
httpPost.setEntity(new StringEntity(enc, ContentType.parse(Constants.CT_FHIR_JSON + "; charset=utf-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(201, status.getStatusLine().getStatusCode());
|
||||
assertEquals(Constants.CT_FHIR_JSON, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
||||
assertEquals("{\"resourceType\":\"OperationOutcome\",\"issue\":[{\"diagnostics\":\"FAMILY\"}]}", responseContent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithJsonNewNoAcceptHeader() throws Exception {
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("FAMILY");
|
||||
String enc = ourCtx.newJsonParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
|
||||
httpPost.setEntity(new StringEntity(enc, ContentType.parse(Constants.CT_FHIR_JSON_NEW + "; charset=utf-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(201, status.getStatusLine().getStatusCode());
|
||||
assertEquals(Constants.CT_FHIR_JSON_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
||||
assertEquals("{\"resourceType\":\"OperationOutcome\",\"issue\":[{\"diagnostics\":\"FAMILY\"}]}", responseContent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithJsonNewWithAcceptHeader() throws Exception {
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("FAMILY");
|
||||
String enc = ourCtx.newJsonParser().encodeResourceToString(p);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
|
||||
httpPost.setEntity(new StringEntity(enc, ContentType.parse(Constants.CT_FHIR_JSON + "; charset=utf-8")));
|
||||
httpPost.addHeader(Constants.HEADER_ACCEPT, Constants.CT_FHIR_JSON_NEW);
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(201, status.getStatusLine().getStatusCode());
|
||||
assertEquals(Constants.CT_FHIR_JSON_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
||||
assertEquals("{\"resourceType\":\"OperationOutcome\",\"issue\":[{\"diagnostics\":\"FAMILY\"}]}", responseContent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithFormatXmlSimple() throws Exception {
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=xml");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, containsString("<Patient xmlns=\"http://hl7.org/fhir\">"));
|
||||
assertThat(responseContent, not(containsString("http://hl7.org/fhir/")));
|
||||
assertEquals(Constants.CT_FHIR_XML_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithFormatXmlLegacy() throws Exception {
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=" + Constants.CT_FHIR_XML);
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, containsString("<Patient xmlns=\"http://hl7.org/fhir\">"));
|
||||
assertThat(responseContent, not(containsString("http://hl7.org/fhir/")));
|
||||
assertEquals(Constants.CT_FHIR_XML, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithFormatXmlNew() throws Exception {
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=" + Constants.CT_FHIR_XML_NEW);
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, containsString("<Patient xmlns=\"http://hl7.org/fhir\">"));
|
||||
assertThat(responseContent, not(containsString("http://hl7.org/fhir/")));
|
||||
assertEquals(Constants.CT_FHIR_XML_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchWithFormatJsonSimple() throws Exception {
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=json");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, containsString("\"resourceType\""));
|
||||
assertEquals(Constants.CT_FHIR_JSON_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithFormatJsonLegacy() throws Exception {
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=" + Constants.CT_FHIR_JSON);
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, containsString("\"resourceType\""));
|
||||
assertEquals(Constants.CT_FHIR_JSON, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithFormatJsonNew() throws Exception {
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=" + Constants.CT_FHIR_JSON_NEW);
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, containsString("\"resourceType\""));
|
||||
assertEquals(Constants.CT_FHIR_JSON_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourServer.stop();
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourPort = PortUtil.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
PatientProvider patientProvider = new PatientProvider();
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||
|
||||
servlet.setResourceProviders(patientProvider);
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
|
||||
}
|
||||
|
||||
public static class PatientProvider implements IResourceProvider {
|
||||
|
||||
@Create()
|
||||
public MethodOutcome create(@ResourceParam Patient theIdParam) {
|
||||
OperationOutcome oo = new OperationOutcome();
|
||||
oo.addIssue().setDiagnostics(theIdParam.getNameFirstRep().getFamily());
|
||||
return new MethodOutcome(new IdType("Patient", "1"), true).setOperationOutcome(oo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Patient> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
@Read()
|
||||
public MyPatientWithExtensions read(@IdParam IdType theIdParam) {
|
||||
MyPatientWithExtensions p0 = new MyPatientWithExtensions();
|
||||
p0.setId(theIdParam);
|
||||
p0.setDateExt(new DateType("2011-01-01"));
|
||||
return p0;
|
||||
}
|
||||
|
||||
@Search
|
||||
public List<IBaseResource> search() {
|
||||
ArrayList<IBaseResource> retVal = new ArrayList<IBaseResource>();
|
||||
|
||||
MyPatientWithExtensions p0 = new MyPatientWithExtensions();
|
||||
p0.setId(new IdType("Patient/0"));
|
||||
p0.setDateExt(new DateType("2011-01-01"));
|
||||
retVal.add(p0);
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.setId(new IdType("Patient/1"));
|
||||
p1.addName().setFamily("The Family");
|
||||
retVal.add(p1);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package org.hl7.fhir.r4.test;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Suite;
|
||||
import org.junit.runners.Suite.SuiteClasses;
|
||||
|
||||
@RunWith(Suite.class)
|
||||
@SuiteClasses({ FluentPathTests.class, NarrativeGeneratorTests.class, /*ShexGeneratorTests.class, StructureMapTests.class, */ TurtleTests.class, GraphQLParserTests.class })
|
||||
public class AllTests {
|
||||
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
package org.hl7.fhir.r4.test;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.hl7.fhir.r4.context.SimpleWorkerContext;
|
||||
import org.hl7.fhir.r4.formats.XmlParser;
|
||||
import org.hl7.fhir.r4.model.Base;
|
||||
import org.hl7.fhir.r4.model.BooleanType;
|
||||
import org.hl7.fhir.r4.model.ExpressionNode;
|
||||
import org.hl7.fhir.r4.model.PrimitiveType;
|
||||
import org.hl7.fhir.r4.model.Resource;
|
||||
import org.hl7.fhir.r4.test.support.TestingUtilities;
|
||||
import org.hl7.fhir.r4.utils.FHIRPathEngine;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.xml.XMLUtil;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class FluentPathTests {
|
||||
|
||||
private static FHIRPathEngine fp;
|
||||
|
||||
@Parameters(name = "{index}: file {0}")
|
||||
public static Iterable<Object[]> data() throws ParserConfigurationException, SAXException, IOException {
|
||||
Document dom = XMLUtil.parseFileToDom(Utilities.path(TestingUtilities. home(), "tests", "resources", "tests-fhir-r4.xml"));
|
||||
|
||||
List<Element> list = new ArrayList<Element>();
|
||||
List<Element> groups = new ArrayList<Element>();
|
||||
XMLUtil.getNamedChildren(dom.getDocumentElement(), "group", groups);
|
||||
for (Element g : groups) {
|
||||
XMLUtil.getNamedChildren(g, "test", list);
|
||||
}
|
||||
|
||||
List<Object[]> objects = new ArrayList<Object[]>(list.size());
|
||||
|
||||
for (Element e : list) {
|
||||
objects.add(new Object[] { getName(e), e });
|
||||
}
|
||||
|
||||
return objects;
|
||||
}
|
||||
|
||||
private static Object getName(Element e) {
|
||||
String s = e.getAttribute("name");
|
||||
if (Utilities.noString(s)) {
|
||||
Element p = (Element) e.getParentNode();
|
||||
int ndx = 0;
|
||||
for (int i = 0; i < p.getChildNodes().getLength(); i++) {
|
||||
Node c = p.getChildNodes().item(i);
|
||||
if (c == e)
|
||||
break;
|
||||
else if (c instanceof Element)
|
||||
ndx++;
|
||||
}
|
||||
s = p.getAttribute("name")+" - "+Integer.toString(ndx+1);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
private final Element test;
|
||||
private final String name;
|
||||
|
||||
public FluentPathTests(String name, Element e) {
|
||||
this.name = name;
|
||||
this.test = e;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void test() throws FileNotFoundException, IOException, FHIRException, org.hl7.fhir.exceptions.FHIRException {
|
||||
if (TestingUtilities.context == null)
|
||||
TestingUtilities.context = SimpleWorkerContext.fromPack(Utilities.path(TestingUtilities.home(), "publish", "definitions.xml.zip"));
|
||||
if (fp == null)
|
||||
fp = new FHIRPathEngine(TestingUtilities.context);
|
||||
String input = test.getAttribute("inputfile");
|
||||
String expression = XMLUtil.getNamedChild(test, "expression").getTextContent();
|
||||
boolean fail = "true".equals(XMLUtil.getNamedChild(test, "expression").getAttribute("invalid"));
|
||||
Resource res = null;
|
||||
|
||||
List<Base> outcome = new ArrayList<Base>();
|
||||
|
||||
ExpressionNode node = fp.parse(expression);
|
||||
try {
|
||||
if (Utilities.noString(input))
|
||||
fp.check(null, null, node);
|
||||
else {
|
||||
res = new XmlParser().parse(new FileInputStream(Utilities.path(TestingUtilities.home(), "publish", input)));
|
||||
fp.check(res, res.getResourceType().toString(), res.getResourceType().toString(), node);
|
||||
}
|
||||
outcome = fp.evaluate(res, node);
|
||||
Assert.assertTrue(String.format("Expected exception parsing %s", expression), !fail);
|
||||
} catch (Exception e) {
|
||||
Assert.assertTrue(String.format("Unexpected exception parsing %s: "+e.getMessage(), expression), fail);
|
||||
}
|
||||
|
||||
if ("true".equals(test.getAttribute("predicate"))) {
|
||||
boolean ok = fp.convertToBoolean(outcome);
|
||||
outcome.clear();
|
||||
outcome.add(new BooleanType(ok));
|
||||
}
|
||||
if (fp.hasLog())
|
||||
System.out.println(fp.takeLog());
|
||||
|
||||
List<Element> expected = new ArrayList<Element>();
|
||||
XMLUtil.getNamedChildren(test, "output", expected);
|
||||
Assert.assertTrue(String.format("Expected %d objects but found %d", expected.size(), outcome.size()), outcome.size() == expected.size());
|
||||
for (int i = 0; i < Math.min(outcome.size(), expected.size()); i++) {
|
||||
String tn = expected.get(i).getAttribute("type");
|
||||
if (!Utilities.noString(tn)) {
|
||||
Assert.assertTrue(String.format("Outcome %d: Type should be %s but was %s", i, tn, outcome.get(i).fhirType()), tn.equals(outcome.get(i).fhirType()));
|
||||
}
|
||||
String v = expected.get(i).getTextContent();
|
||||
if (!Utilities.noString(v)) {
|
||||
Assert.assertTrue(String.format("Outcome %d: Value should be a primitive type but was %s", i, outcome.get(i).fhirType()), outcome.get(i) instanceof PrimitiveType);
|
||||
Assert.assertTrue(String.format("Outcome %d: Value should be %s but was %s", i, v, outcome.get(i).toString()), v.equals(((PrimitiveType)outcome.get(i)).asStringValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,200 +0,0 @@
|
||||
package org.hl7.fhir.r4.test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.r4.context.SimpleWorkerContext;
|
||||
import org.hl7.fhir.r4.formats.XmlParser;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.DomainResource;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.hl7.fhir.r4.model.Resource;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleLinkComponent;
|
||||
import org.hl7.fhir.r4.model.Bundle.SearchEntryMode;
|
||||
import org.hl7.fhir.r4.test.support.TestingUtilities;
|
||||
import org.hl7.fhir.r4.utils.GraphQLEngine;
|
||||
import org.hl7.fhir.r4.utils.GraphQLEngine.IGraphQLStorageServices;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.graphql.Argument;
|
||||
import org.hl7.fhir.utilities.graphql.EGraphEngine;
|
||||
import org.hl7.fhir.utilities.graphql.EGraphQLException;
|
||||
import org.hl7.fhir.utilities.graphql.NameValue;
|
||||
import org.hl7.fhir.utilities.graphql.Package;
|
||||
import org.hl7.fhir.utilities.graphql.Parser;
|
||||
import org.hl7.fhir.utilities.xml.XMLUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class GraphQLEngineTests implements IGraphQLStorageServices {
|
||||
|
||||
@Parameters(name = "{index}: {0}")
|
||||
public static Iterable<Object[]> data() throws FileNotFoundException, IOException, ParserConfigurationException, SAXException {
|
||||
Document tests = XMLUtil.parseFileToDom(Utilities.path(TestingUtilities.home(), "tests", "graphql", "manifest.xml"));
|
||||
Element test = XMLUtil.getFirstChild(tests.getDocumentElement());
|
||||
List<Object[]> objects = new ArrayList<Object[]>();
|
||||
while (test != null && test.getNodeName().equals("test")) {
|
||||
objects.add(new Object[] { test.getAttribute("name"), test.getAttribute("source"), test.getAttribute("output"),
|
||||
test.getAttribute("context"), test.getAttribute("resource"), test.getAttribute("operation")} );
|
||||
test = XMLUtil.getNextSibling(test);
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
|
||||
private final String name;
|
||||
private String source;
|
||||
private String output;
|
||||
private String context;
|
||||
private String resource;
|
||||
private String operation;
|
||||
|
||||
public GraphQLEngineTests(String name, String source, String output, String context, String resource, String operation) {
|
||||
this.name = name;
|
||||
this.source = source;
|
||||
this.output = output;
|
||||
this.context = context;
|
||||
this.resource = resource;
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
String filename = null;
|
||||
if (!Utilities.noString(context)) {
|
||||
String[] parts = context.split("/");
|
||||
if (parts.length != 3)
|
||||
throw new Exception("not done yet "+source+" "+output+" "+context);
|
||||
if (!Utilities.noString(resource))
|
||||
filename = Utilities.path(TestingUtilities.home(), "publish", resource+".xml");
|
||||
else
|
||||
filename = Utilities.path(TestingUtilities.home(), "publish", parts[0].toLowerCase()+"-"+parts[1].toLowerCase()+".xml");
|
||||
}
|
||||
|
||||
if (TestingUtilities.context == null)
|
||||
TestingUtilities.context = SimpleWorkerContext.fromPack(Utilities.path(TestingUtilities.home(), "publish", "definitions.xml.zip"));
|
||||
|
||||
GraphQLEngine gql = new GraphQLEngine(TestingUtilities.context);
|
||||
gql.setServices(this);
|
||||
if (!Utilities.noString(filename))
|
||||
gql.setFocus(new XmlParser().parse(new FileInputStream(filename)));
|
||||
gql.setGraphQL(Parser.parseFile(Utilities.path(TestingUtilities.home(), "tests", "graphql", source)));
|
||||
gql.getGraphQL().setOperationName(operation);
|
||||
gql.getGraphQL().getVariables().add(new Argument("var", new NameValue("true")));
|
||||
boolean ok = false;
|
||||
String msg = null;
|
||||
try {
|
||||
gql.execute();
|
||||
ok = true;
|
||||
} catch (Exception e) {
|
||||
if (!output.equals("$error"))
|
||||
e.printStackTrace();
|
||||
ok = false;
|
||||
msg = e.getMessage();
|
||||
}
|
||||
if (ok) {
|
||||
Assert.assertTrue("Expected to fail, but didn't", !output.equals("$error"));
|
||||
StringBuilder str = new StringBuilder();
|
||||
gql.getOutput().write(str, 0);
|
||||
TextFile.stringToFile(str.toString(), Utilities.path(TestingUtilities.home(), "tests", "graphql", output+".out"));
|
||||
msg = TestingUtilities.checkJsonIsSame(Utilities.path(TestingUtilities.home(), "tests", "graphql", output+".out"),Utilities.path(TestingUtilities.home(), "tests", "graphql", output));
|
||||
Assert.assertTrue(msg, Utilities.noString(msg));
|
||||
}
|
||||
else
|
||||
Assert.assertTrue("Error, but proper output was expected ("+msg+")", output.equals("$error"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource lookup(Object appInfo, String type, String id) throws FHIRException {
|
||||
try {
|
||||
String filename = Utilities.path(TestingUtilities.home(), "publish", type.toLowerCase()+'-'+id.toLowerCase()+".xml");
|
||||
if (new File(filename).exists())
|
||||
return new XmlParser().parse(new FileInputStream(filename));
|
||||
else
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
throw new FHIRException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReferenceResolution lookup(Object appInfo, Resource context, Reference reference) throws FHIRException {
|
||||
try {
|
||||
if (reference.getReference().startsWith("#")) {
|
||||
if (!(context instanceof DomainResource))
|
||||
return null;
|
||||
for (Resource r : ((DomainResource)context).getContained()) {
|
||||
if (('#'+r.getId()).equals(reference.getReference())) {
|
||||
return new ReferenceResolution(context, r);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String[] parts = reference.getReference().split("/");
|
||||
String filename = Utilities.path(TestingUtilities.home(), "publish", parts[0].toLowerCase()+'-'+parts[1].toLowerCase()+".xml");
|
||||
if (new File(filename).exists())
|
||||
return new ReferenceResolution(null, new XmlParser().parse(new FileInputStream(filename)));
|
||||
}
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
throw new FHIRException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void listResources(Object appInfo, String type, List<Argument> searchParams, List<Resource> matches) throws FHIRException {
|
||||
try {
|
||||
if (type.equals("Condition"))
|
||||
matches.add(new XmlParser().parse(new FileInputStream(Utilities.path(TestingUtilities.home(), "publish", "condition-example.xml"))));
|
||||
else if (type.equals("Patient")) {
|
||||
matches.add(new XmlParser().parse(new FileInputStream(Utilities.path(TestingUtilities.home(), "publish", "patient-example.xml"))));
|
||||
matches.add(new XmlParser().parse(new FileInputStream(Utilities.path(TestingUtilities.home(), "publish", "patient-example-xds.xml"))));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new FHIRException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle search(Object appInfo, String type, List<Argument> searchParams) throws FHIRException {
|
||||
try {
|
||||
Bundle bnd = new Bundle();
|
||||
BundleLinkComponent bl = bnd.addLink();
|
||||
bl.setRelation("next");
|
||||
bl.setUrl("http://test.fhir.org/r3/Patient?_format=text/xhtml&search-id=77c97e03-8a6c-415f-a63d-11c80cf73f&&active=true&_sort=_id&search-offset=50&_count=50");
|
||||
bl = bnd.addLink();
|
||||
bl.setRelation("self");
|
||||
bl.setUrl("http://test.fhir.org/r3/Patient?_format=text/xhtml&search-id=77c97e03-8a6c-415f-a63d-11c80cf73f&&active=true&_sort=_id&search-offset=0&_count=50");
|
||||
BundleEntryComponent be = bnd.addEntry();
|
||||
be.setFullUrl("http://hl7.org/fhir/Patient/example");
|
||||
be.setResource(new XmlParser().parse(new FileInputStream(Utilities.path(TestingUtilities.home(), "publish", "patient-example.xml"))));
|
||||
be = bnd.addEntry();
|
||||
be.setFullUrl("http://hl7.org/fhir/Patient/example");
|
||||
be.setResource(new XmlParser().parse(new FileInputStream(Utilities.path(TestingUtilities.home(), "publish", "patient-example-xds.xml"))));
|
||||
be.getSearch().setScore(0.5);
|
||||
be.getSearch().setMode(SearchEntryMode.MATCH);
|
||||
bnd.setTotal(50);
|
||||
return bnd;
|
||||
} catch (Exception e) {
|
||||
throw new FHIRException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
package org.hl7.fhir.r4.test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r4.test.support.TestingUtilities;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.graphql.EGraphEngine;
|
||||
import org.hl7.fhir.utilities.graphql.EGraphQLException;
|
||||
import org.hl7.fhir.utilities.graphql.Package;
|
||||
import org.hl7.fhir.utilities.graphql.Parser;
|
||||
import org.hl7.fhir.utilities.xml.XMLUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class GraphQLParserTests {
|
||||
|
||||
@Parameters(name = "{index}: {0}")
|
||||
public static Iterable<Object[]> data() throws FileNotFoundException, IOException {
|
||||
String src = TextFile.fileToString(Utilities.path(TestingUtilities.home(), "tests", "graphql", "parser-tests.gql"));
|
||||
String[] tests = src.split("###");
|
||||
int i = 0;
|
||||
for (String s : tests)
|
||||
if (!Utilities.noString(s.trim()))
|
||||
i++;
|
||||
List<Object[]> objects = new ArrayList<Object[]>(i);
|
||||
i = 0;
|
||||
for (String s : tests) {
|
||||
if (!Utilities.noString(s.trim())) {
|
||||
int l = s.indexOf('\r');
|
||||
objects.add(new Object[] { s.substring(0, l), s.substring(l+2).trim()});
|
||||
}
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
|
||||
private final String test;
|
||||
private final String name;
|
||||
|
||||
public GraphQLParserTests(String name, String test) {
|
||||
this.name = name;
|
||||
this.test = test;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws IOException, EGraphQLException, EGraphEngine {
|
||||
Package doc = Parser.parse(test);
|
||||
Assert.assertTrue(doc != null);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
package org.hl7.fhir.r4.test;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.hl7.fhir.r4.context.SimpleWorkerContext;
|
||||
import org.hl7.fhir.r4.formats.XmlParser;
|
||||
import org.hl7.fhir.r4.model.DomainResource;
|
||||
import org.hl7.fhir.r4.test.support.TestingUtilities;
|
||||
import org.hl7.fhir.r4.utils.EOperationOutcome;
|
||||
import org.hl7.fhir.r4.utils.NarrativeGenerator;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
public class NarrativeGeneratorTests {
|
||||
|
||||
private NarrativeGenerator gen;
|
||||
|
||||
@Before
|
||||
public void setUp() throws FileNotFoundException, IOException, FHIRException {
|
||||
if (TestingUtilities.context == null)
|
||||
TestingUtilities.context = SimpleWorkerContext.fromPack(Utilities.path(TestingUtilities.home(), "publish", "definitions.xml.zip"));
|
||||
if (gen == null)
|
||||
gen = new NarrativeGenerator("", null, TestingUtilities.context);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws FileNotFoundException, IOException, XmlPullParserException, EOperationOutcome, FHIRException {
|
||||
process(Utilities.path(TestingUtilities.home(), "source", "questionnaireresponse", "questionnaireresponse-example-f201-lifelines.xml"));
|
||||
}
|
||||
|
||||
private void process(String path) throws FileNotFoundException, IOException, XmlPullParserException, EOperationOutcome, FHIRException {
|
||||
XmlParser p = new XmlParser();
|
||||
DomainResource r = (DomainResource) p.parse(new FileInputStream(path));
|
||||
gen.generate(r);
|
||||
FileOutputStream s = new FileOutputStream(Utilities.path(TestingUtilities.temp(), "gen.xml"));
|
||||
new XmlParser().compose(s, r, true);
|
||||
s.close();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,940 +0,0 @@
|
||||
package org.hl7.fhir.r4.test;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r4.conformance.ProfileComparer;
|
||||
import org.hl7.fhir.r4.conformance.ProfileComparer.ProfileComparison;
|
||||
import org.hl7.fhir.r4.conformance.ProfileUtilities;
|
||||
import org.hl7.fhir.r4.context.SimpleWorkerContext;
|
||||
import org.hl7.fhir.r4.formats.IParser.OutputStyle;
|
||||
import org.hl7.fhir.r4.formats.XmlParser;
|
||||
import org.hl7.fhir.r4.model.Base;
|
||||
import org.hl7.fhir.r4.model.CodeType;
|
||||
import org.hl7.fhir.r4.model.ElementDefinition;
|
||||
import org.hl7.fhir.r4.model.ElementDefinition.DiscriminatorType;
|
||||
import org.hl7.fhir.r4.model.ElementDefinition.SlicingRules;
|
||||
import org.hl7.fhir.r4.model.Enumerations.BindingStrength;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition.TypeDerivationRule;
|
||||
import org.hl7.fhir.r4.test.support.TestingUtilities;
|
||||
import org.hl7.fhir.r4.utils.EOperationOutcome;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.utilities.CSFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r4.utils.SnomedExpressions;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
public class ProfileUtilitiesTests {
|
||||
|
||||
// private String root;
|
||||
// private SimpleWorkerContext context;
|
||||
// private ProfileComparer comp;
|
||||
//
|
||||
//// public ProfileUtilitiesTests(String root) {
|
||||
//// super();
|
||||
//// this.root = root;
|
||||
//// }
|
||||
//
|
||||
//// public ProfileUtilitiesTests() {
|
||||
//// super();
|
||||
//// root = TestingUtilities.home();
|
||||
////
|
||||
//// }
|
||||
//
|
||||
// public static void main(String[] args) throws EOperationOutcome, Exception {
|
||||
// // new ProfileUtilitiesTests().execute(args);
|
||||
// ProfileUtilitiesTests put = new ProfileUtilitiesTests();
|
||||
// put.root = "C:\\work\\org.hl7.fhir\\build\\publish";
|
||||
// put.testSnapshotGeneration();
|
||||
// // StructureDefinition p = (StructureDefinition) new XmlParser().parse(new FileInputStream("C:\\work\\org.hl7.fhir\\build\\publish\\lipid-report-cholesterol.profile.xml"));
|
||||
// // new ProfileUtilities(context, messages, null).generateSchematrons(new FileOutputStream("c:\\temp\\test.sch"), p);
|
||||
// }
|
||||
//
|
||||
// public void execute(String[] args) throws FileNotFoundException, IOException, FHIRException {
|
||||
// System.out.println("loading context");
|
||||
// context = SimpleWorkerContext.fromPack(Utilities.path(root, "validation.zip"));
|
||||
// comp = new ProfileComparer(context);
|
||||
//
|
||||
// compare("patient-daf-dafpatient.profile.xml", "patient-qicore-qicore-patient.profile.xml");
|
||||
// compare("encounter-daf-dafencounter.profile.xml", "encounter-qicore-qicore-encounter.profile.xml");
|
||||
// compare("substance-daf-dafsubstance.profile.xml", "substance-qicore-qicore-substance.profile.xml");
|
||||
// compare("medication-daf-dafmedication.profile.xml", "medication-qicore-qicore-medication.profile.xml");
|
||||
// compare("procedure-daf-dafprocedure.profile.xml", "procedure-qicore-qicore-procedure.profile.xml");
|
||||
// compare("familymemberhistory-daf-daffamilymemberhistory.profile.xml", "familymemberhistory-qicore-qicore-familymemberhistory.profile.xml");
|
||||
// compare("immunization-daf-dafimmunization.profile.xml", "immunization-qicore-qicore-immunization.profile.xml");
|
||||
// compare("condition-daf-dafcondition.profile.xml", "condition-qicore-qicore-condition.profile.xml");
|
||||
// compare("allergyintolerance-daf-dafallergyintolerance.profile.xml", "allergyintolerance-qicore-qicore-allergyintolerance.profile.xml");
|
||||
// compare("medicationadministration-daf-dafmedicationadministration.profile.xml", "medicationadministration-qicore-qicore-medicationadministration.profile.xml");
|
||||
// compare("medicationdispense-daf-dafmedicationdispense.profile.xml", "medicationdispense-qicore-qicore-medicationdispense.profile.xml");
|
||||
// compare("medicationprescription-daf-dafmedicationprescription.profile.xml", "medicationprescription-qicore-qicore-medicationprescription.profile.xml");
|
||||
// compare("medicationstatement-daf-dafmedicationstatement.profile.xml", "medicationstatement-qicore-qicore-medicationstatement.profile.xml");
|
||||
// compare("observation-daf-smokingstatus-dafsmokingstatus.profile.xml", "observation-qicore-qicore-observation.profile.xml");
|
||||
// compare("observation-daf-vitalsigns-dafvitalsigns.profile.xml", "observation-qicore-qicore-observation.profile.xml");
|
||||
//// compare("observation-daf-results-dafresultobs.profile.xml", "observation-qicore-qicore-observation.profile.xml");
|
||||
//// compare("diagnosticorder-daf-dafdiagnosticorder.profile.xml", "diagnosticorder-qicore-qicore-diagnosticorder.profile.xml");
|
||||
//// compare("diagnosticreport-daf-dafdiagnosticreport.profile.xml", "diagnosticreport-qicore-qicore-diagnosticreport.profile.xml");
|
||||
//
|
||||
// System.out.println("processing output");
|
||||
// for (ProfileComparison outcome : comp.getComparisons()) {
|
||||
// if (outcome.getSubset() != null)
|
||||
// new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream("C:\\temp\\intersection-"+outcome.getId()+".xml"), outcome.getSubset());
|
||||
// if (outcome.getSuperset() != null)
|
||||
// new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream("C:\\temp\\union-"+outcome.getId()+".xml"), outcome.getSuperset());
|
||||
//
|
||||
// System.out.println("\r\n"+outcome.getId()+": Comparison of "+outcome.getLeft().getUrl()+" and "+outcome.getRight().getUrl());
|
||||
// for (ValidationMessage vm : outcome.getMessages())
|
||||
// if (vm.getLevel() == IssueSeverity.INFORMATION)
|
||||
// System.out.println(vm.summary());
|
||||
// for (ValidationMessage vm : outcome.getMessages())
|
||||
// if (vm.getLevel() == IssueSeverity.WARNING)
|
||||
// System.out.println(vm.summary());
|
||||
// for (ValidationMessage vm : outcome.getMessages())
|
||||
// if (vm.getLevel() == IssueSeverity.ERROR)
|
||||
// System.out.println(vm.summary());
|
||||
// for (ValidationMessage vm : outcome.getMessages())
|
||||
// if (vm.getLevel() == IssueSeverity.FATAL)
|
||||
// System.out.println(vm.summary());
|
||||
// System.out.println("done. "+Integer.toString(outcome.getMessages().size())+" messages");
|
||||
// System.out.println("=================================================================");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void compare(String fn1, String fn2) throws FHIRFormatError, FileNotFoundException, IOException, DefinitionException {
|
||||
// System.out.println("Compare "+fn1+" to "+fn2);
|
||||
// System.out.println(" .. load");
|
||||
// StructureDefinition left = (StructureDefinition) new XmlParser().parse(new FileInputStream(Utilities.path(root, fn1)));
|
||||
// StructureDefinition right = (StructureDefinition) new XmlParser().parse(new FileInputStream(Utilities.path(root, fn2)));
|
||||
// System.out.println(" .. compare");
|
||||
// comp.compareProfiles(left, right);
|
||||
//
|
||||
// }
|
||||
//
|
||||
// public void testSnapshotGeneration() throws EOperationOutcome, Exception {
|
||||
// System.out.println("Loading");
|
||||
// context = SimpleWorkerContext.fromPack(Utilities.path(root, "definitions.xml.zip"));
|
||||
// System.out.println("Loaded "+Integer.toString(context.totalCount())+" resources");
|
||||
//
|
||||
// // simple tests
|
||||
// testSimple();
|
||||
// testSimple2();
|
||||
// testCardinalityChange();
|
||||
// testDocumentationAppend();
|
||||
// textTypeNarrowing1();
|
||||
// textTypeNarrowing2();
|
||||
// testMapping();
|
||||
//
|
||||
// // ok, now we test walking into a new type:
|
||||
// testTypeWalk();
|
||||
// // todo: testTypeWalk2();
|
||||
//
|
||||
// // slicing tests
|
||||
// testSlicingSimple();
|
||||
// testSlicingExtension(false);
|
||||
// testSlicingExtension(true);
|
||||
// testSlicingExtensionComplex(true);
|
||||
// testSlicingExtensionComplex(false);
|
||||
// testSlicingTask8742();
|
||||
// System.out.println("Success");
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * This is simple: we just create an empty differential, generate the snapshot, and then insist it must match the base
|
||||
// *
|
||||
// * @param context2
|
||||
// * @
|
||||
// * @throws EOperationOutcome
|
||||
// */
|
||||
@Test
|
||||
public void testSimple() throws FHIRException, FileNotFoundException, IOException {
|
||||
if (TestingUtilities.context == null)
|
||||
TestingUtilities.context = SimpleWorkerContext.fromPack(Utilities.path(TestingUtilities.home(), "publish", "definitions.xml.zip"));
|
||||
|
||||
StructureDefinition focus = new StructureDefinition();
|
||||
StructureDefinition base = TestingUtilities.context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/Patient").copy();
|
||||
focus.setUrl(Utilities.makeUuidUrn());
|
||||
focus.setBaseDefinition(base.getUrl());
|
||||
focus.setType("Patient");
|
||||
focus.setDerivation(TypeDerivationRule.CONSTRAINT);
|
||||
List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
|
||||
new ProfileUtilities(TestingUtilities.context, messages, null).generateSnapshot(base, focus, focus.getUrl(), "Simple Test");
|
||||
|
||||
boolean ok = base.getSnapshot().getElement().size() == focus.getSnapshot().getElement().size();
|
||||
for (int i = 0; i < base.getSnapshot().getElement().size(); i++) {
|
||||
ElementDefinition b = base.getSnapshot().getElement().get(i);
|
||||
ElementDefinition f = focus.getSnapshot().getElement().get(i);
|
||||
if (ok) {
|
||||
if (!f.hasBase())
|
||||
ok = false;
|
||||
else if (!b.getPath().equals(f.getPath()))
|
||||
ok = false;
|
||||
else {
|
||||
b.setBase(null);
|
||||
f.setBase(null);
|
||||
ok = Base.compareDeep(b, f, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
compareXml(base, focus);
|
||||
throw new FHIRException("Snap shot generation simple test failed");
|
||||
} else
|
||||
System.out.println("Snap shot generation simple test passed");
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// /**
|
||||
// * This is simple: we just create an empty differential, generate the snapshot, and then insist it must match the base. for a different resource with recursion
|
||||
// *
|
||||
// * @param context2
|
||||
// * @
|
||||
// * @throws EOperationOutcome
|
||||
// */
|
||||
@Test
|
||||
public void testSimple2() throws EOperationOutcome, Exception {
|
||||
if (TestingUtilities.context == null)
|
||||
TestingUtilities.context = SimpleWorkerContext.fromPack(Utilities.path(TestingUtilities.home(), "publish", "definitions.xml.zip"));
|
||||
|
||||
StructureDefinition focus = new StructureDefinition();
|
||||
StructureDefinition base = TestingUtilities.context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/ValueSet").copy();
|
||||
focus.setUrl(Utilities.makeUuidUrn());
|
||||
focus.setBaseDefinition(base.getUrl());
|
||||
focus.setType(base.getType());
|
||||
focus.setDerivation(TypeDerivationRule.CONSTRAINT);
|
||||
List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
|
||||
new ProfileUtilities(TestingUtilities.context, messages, null).generateSnapshot(base, focus, focus.getUrl(), "Simple Test" );
|
||||
|
||||
boolean ok = base.getSnapshot().getElement().size() == focus.getSnapshot().getElement().size();
|
||||
for (int i = 0; i < base.getSnapshot().getElement().size(); i++) {
|
||||
if (ok) {
|
||||
ElementDefinition b = base.getSnapshot().getElement().get(i);
|
||||
ElementDefinition f = focus.getSnapshot().getElement().get(i);
|
||||
if (!f.hasBase() || !b.getPath().equals(f.getBase().getPath()))
|
||||
ok = false;
|
||||
else {
|
||||
f.setBase(null);
|
||||
ok = Base.compareDeep(b, f, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
compareXml(base, focus);
|
||||
throw new FHIRException("Snap shot generation simple test failed");
|
||||
} else
|
||||
System.out.println("Snap shot generation simple test passed");
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Change one cardinality.
|
||||
// *
|
||||
// * @param context2
|
||||
// * @
|
||||
// * @throws EOperationOutcome
|
||||
// */
|
||||
// private void testCardinalityChange() throws EOperationOutcome, Exception {
|
||||
// StructureDefinition focus = new StructureDefinition();
|
||||
// StructureDefinition base = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/Patient").copy();
|
||||
// focus.setUrl(Utilities.makeUuidUrn());
|
||||
// focus.setBaseDefinition(base.getUrl());
|
||||
// focus.setType(base.getType());
|
||||
// focus.setDerivation(TypeDerivationRule.CONSTRAINT);
|
||||
// ElementDefinition id = focus.getDifferential().addElement();
|
||||
// id.setPath("Patient.identifier");
|
||||
// id.setMin(1);
|
||||
// List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
|
||||
// new ProfileUtilities(context, messages, null).generateSnapshot(base, focus, focus.getUrl(), "Simple Test" );
|
||||
//
|
||||
// boolean ok = base.getSnapshot().getElement().size() == focus.getSnapshot().getElement().size();
|
||||
// for (int i = 0; i < base.getSnapshot().getElement().size(); i++) {
|
||||
// if (ok) {
|
||||
// ElementDefinition b = base.getSnapshot().getElement().get(i);
|
||||
// ElementDefinition f = focus.getSnapshot().getElement().get(i);
|
||||
// if (!f.hasBase() || !b.getPath().equals(f.getBase().getPath()))
|
||||
// ok = false;
|
||||
// else {
|
||||
// f.setBase(null);
|
||||
// if (f.getPath().equals("Patient.identifier")) {
|
||||
// ok = f.getMin() == 1;
|
||||
// if (ok)
|
||||
// f.setMin(0);
|
||||
// }
|
||||
// ok = ok && Base.compareDeep(b, f, true);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (!ok) {
|
||||
// compareXml(base, focus);
|
||||
// throw new FHIRException("Snap shot generation chenge cardinality test failed");
|
||||
// } else
|
||||
// System.out.println("Snap shot generation chenge cardinality test passed");
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * check that documentation appending is working
|
||||
// *
|
||||
// * @param context2
|
||||
// * @
|
||||
// * @throws EOperationOutcome
|
||||
// */
|
||||
// private void testDocumentationAppend() throws EOperationOutcome, Exception {
|
||||
// StructureDefinition focus = new StructureDefinition();
|
||||
// StructureDefinition base = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/Patient").copy();
|
||||
// focus.setUrl(Utilities.makeUuidUrn());
|
||||
// focus.setBaseDefinition(base.getUrl());
|
||||
// focus.setType(base.getType());
|
||||
// focus.setDerivation(TypeDerivationRule.CONSTRAINT);
|
||||
// ElementDefinition id = focus.getDifferential().addElement();
|
||||
// id.setPath("Patient.identifier");
|
||||
// id.setDefinition("... some more doco");
|
||||
// List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
|
||||
// new ProfileUtilities(context, messages, null).generateSnapshot(base, focus, focus.getUrl(), "Simple Test" );
|
||||
//
|
||||
// boolean ok = base.getSnapshot().getElement().size() == focus.getSnapshot().getElement().size();
|
||||
// for (int i = 0; i < base.getSnapshot().getElement().size(); i++) {
|
||||
// if (ok) {
|
||||
// ElementDefinition b = base.getSnapshot().getElement().get(i);
|
||||
// ElementDefinition f = focus.getSnapshot().getElement().get(i);
|
||||
// if (!f.hasBase() || !b.getPath().equals(f.getBase().getPath()))
|
||||
// ok = false;
|
||||
// else {
|
||||
// f.setBase(null);
|
||||
// if (f.getPath().equals("Patient.identifier")) {
|
||||
// ok = f.getDefinition().length() > b.getDefinition().length();
|
||||
// if (ok) {
|
||||
// f.setDefinition(null);
|
||||
// b.setDefinition(null);
|
||||
// }
|
||||
// }
|
||||
// ok = ok && Base.compareDeep(b, f, true);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (!ok) {
|
||||
// compareXml(base, focus);
|
||||
// throw new FHIRException("Snap shot generation documentation append failed");
|
||||
// } else
|
||||
// System.out.println("Snap shot generation documentation append test passed");
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * check that narrowing types is working
|
||||
// * this one doesn't rename the path
|
||||
// *
|
||||
// * @param context2
|
||||
// * @
|
||||
// * @throws EOperationOutcome
|
||||
// */
|
||||
// private void textTypeNarrowing1() throws EOperationOutcome, Exception {
|
||||
// StructureDefinition focus = new StructureDefinition();
|
||||
// StructureDefinition base = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/Patient").copy();
|
||||
// focus.setUrl(Utilities.makeUuidUrn());
|
||||
// focus.setBaseDefinition(base.getUrl());
|
||||
// focus.setType(base.getType());
|
||||
// focus.setDerivation(TypeDerivationRule.CONSTRAINT);
|
||||
// ElementDefinition id = focus.getDifferential().addElement();
|
||||
// id.setPath("Patient.deceased[x]");
|
||||
// id.addType().setCode("dateTime");
|
||||
// List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
|
||||
// new ProfileUtilities(context, messages, null).generateSnapshot(base, focus, focus.getUrl(), "Simple Test" );
|
||||
//
|
||||
// boolean ok = base.getSnapshot().getElement().size() == focus.getSnapshot().getElement().size();
|
||||
// for (int i = 0; i < base.getSnapshot().getElement().size(); i++) {
|
||||
// if (ok) {
|
||||
// ElementDefinition b = base.getSnapshot().getElement().get(i);
|
||||
// ElementDefinition f = focus.getSnapshot().getElement().get(i);
|
||||
// if (!f.hasBase() || !b.getPath().equals(f.getBase().getPath()))
|
||||
// ok = false;
|
||||
// else {
|
||||
// f.setBase(null);
|
||||
// if (f.getPath().equals("Patient.deceasedDateTime")) {
|
||||
// ok = f.getType().size() == 1 && f.getType().get(0).getCode().equals("dateTime");
|
||||
// if (ok) {
|
||||
// f.getType().clear();
|
||||
// b.getType().clear();
|
||||
// f.setPath(b.getPath());
|
||||
// }
|
||||
// }
|
||||
// ok = ok && Base.compareDeep(b, f, true);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (!ok) {
|
||||
// compareXml(base, focus);
|
||||
// throw new FHIRException("Snap shot generation narrow type 1 failed");
|
||||
// } else
|
||||
// System.out.println("Snap shot generation narrow type 1 test passed");
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * check that narrowing types is working
|
||||
// * this one renames the path
|
||||
// *
|
||||
// * @param context2
|
||||
// * @
|
||||
// * @throws EOperationOutcome
|
||||
// */
|
||||
// private void textTypeNarrowing2() throws EOperationOutcome, Exception {
|
||||
// StructureDefinition focus = new StructureDefinition();
|
||||
// StructureDefinition base = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/Patient").copy();
|
||||
// focus.setUrl(Utilities.makeUuidUrn());
|
||||
// focus.setBaseDefinition(base.getUrl());
|
||||
// focus.setType(base.getType());
|
||||
// focus.setDerivation(TypeDerivationRule.CONSTRAINT);
|
||||
// ElementDefinition id = focus.getDifferential().addElement();
|
||||
// id.setPath("Patient.deceasedDateTime");
|
||||
// id.addType().setCode("dateTime");
|
||||
// List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
|
||||
// new ProfileUtilities(context, messages, null).generateSnapshot(base, focus, focus.getUrl(), "Simple Test" );
|
||||
//
|
||||
// boolean ok = base.getSnapshot().getElement().size() == focus.getSnapshot().getElement().size();
|
||||
// for (int i = 0; i < base.getSnapshot().getElement().size(); i++) {
|
||||
// if (ok) {
|
||||
// ElementDefinition b = base.getSnapshot().getElement().get(i);
|
||||
// ElementDefinition f = focus.getSnapshot().getElement().get(i);
|
||||
// if (!f.hasBase() || !b.getPath().equals(f.getBase().getPath()))
|
||||
// ok = false;
|
||||
// else {
|
||||
// f.setBase(null);
|
||||
// if (f.getPath().equals("Patient.deceasedDateTime")) {
|
||||
// ok = f.getType().size() == 1 && f.getType().get(0).getCode().equals("dateTime");
|
||||
// if (ok) {
|
||||
// f.getType().clear();
|
||||
// b.getType().clear();
|
||||
// f.setPath(b.getPath());
|
||||
// }
|
||||
// }
|
||||
// ok = ok && Base.compareDeep(b, f, true);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (!ok) {
|
||||
// compareXml(base, focus);
|
||||
// throw new FHIRException("Snap shot generation narrow type 2 failed");
|
||||
// } else
|
||||
// System.out.println("Snap shot generation narrow type 2 test passed");
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * check that mapping resolution is working
|
||||
// *
|
||||
// * @param context2
|
||||
// * @
|
||||
// * @throws EOperationOutcome
|
||||
// */
|
||||
// private void testMapping() throws EOperationOutcome, Exception {
|
||||
// StructureDefinition focus = new StructureDefinition();
|
||||
// StructureDefinition base = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/Patient").copy();
|
||||
// focus.setUrl(Utilities.makeUuidUrn());
|
||||
// focus.setBaseDefinition(base.getUrl());
|
||||
// focus.setType(base.getType());
|
||||
// focus.setDerivation(TypeDerivationRule.CONSTRAINT);
|
||||
// ElementDefinition id = focus.getDifferential().addElement();
|
||||
// id.setPath("Patient.identifier");
|
||||
// id.addMapping().setIdentity("rim").setMap("test");
|
||||
// List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
|
||||
// new ProfileUtilities(context, messages, null).generateSnapshot(base, focus, focus.getUrl(), "Simple Test" );
|
||||
//
|
||||
// boolean ok = base.getSnapshot().getElement().size() == focus.getSnapshot().getElement().size();
|
||||
// for (int i = 0; i < base.getSnapshot().getElement().size(); i++) {
|
||||
// if (ok) {
|
||||
// ElementDefinition b = base.getSnapshot().getElement().get(i);
|
||||
// ElementDefinition f = focus.getSnapshot().getElement().get(i);
|
||||
// if (!f.hasBase() || !b.getPath().equals(f.getBase().getPath()))
|
||||
// ok = false;
|
||||
// else {
|
||||
// f.setBase(null);
|
||||
// if (f.getPath().equals("Patient.identifier")) {
|
||||
// ok = f.getMapping().size() > b.getMapping().size();
|
||||
// if (ok) {
|
||||
// f.getMapping().clear();
|
||||
// b.getMapping().clear();
|
||||
// }
|
||||
// }
|
||||
// ok = ok && Base.compareDeep(b, f, true);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (!ok) {
|
||||
// compareXml(base, focus);
|
||||
// throw new FHIRException("Snap shot generation mapping changes failed");
|
||||
// } else
|
||||
// System.out.println("Snap shot generation mapping changes test passed");
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Walking into a type
|
||||
// *
|
||||
// * @param context2
|
||||
// * @
|
||||
// * @throws EOperationOutcome
|
||||
// */
|
||||
// private void testTypeWalk() throws EOperationOutcome, Exception {
|
||||
// StructureDefinition focus = new StructureDefinition();
|
||||
// StructureDefinition base = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/Patient").copy();
|
||||
// focus.setUrl(Utilities.makeUuidUrn());
|
||||
// focus.setBaseDefinition(base.getUrl());
|
||||
// focus.setType(base.getType());
|
||||
// focus.setDerivation(TypeDerivationRule.CONSTRAINT);
|
||||
// ElementDefinition id = focus.getDifferential().addElement();
|
||||
// id.setPath("Patient.identifier");
|
||||
// id.setMustSupport(true);
|
||||
// id = focus.getDifferential().addElement();
|
||||
// id.setPath("Patient.identifier.system");
|
||||
// id.setMustSupport(true);
|
||||
// List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
|
||||
// new ProfileUtilities(context, messages, null).generateSnapshot(base, focus, focus.getUrl(), "Simple Test" );
|
||||
//
|
||||
// // the derived should be 8 longer
|
||||
// boolean ok = base.getSnapshot().getElement().size() == focus.getSnapshot().getElement().size() - 8;
|
||||
// for (int i = 0; i < base.getSnapshot().getElement().size(); i++) {
|
||||
// if (ok) {
|
||||
// ElementDefinition b = base.getSnapshot().getElement().get(i);
|
||||
// ElementDefinition f = focus.getSnapshot().getElement().get(i <= 9 ? i : i + 8);
|
||||
// if (!f.hasBase() || !b.getPath().equals(f.getBase().getPath()))
|
||||
// ok = false;
|
||||
// else {
|
||||
// f.setBase(null);
|
||||
// if (f.getPath().equals("Patient.identifier")) {
|
||||
// ok = f.getMustSupport() && !b.getMustSupport();
|
||||
// if (ok) {
|
||||
// f.setMustSupportElement(null);
|
||||
// }
|
||||
// }
|
||||
// ok = Base.compareDeep(b, f, true);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (!ok) {
|
||||
// compareXml(base, focus);
|
||||
// throw new FHIRException("Snap shot generation simple test failed");
|
||||
// } else
|
||||
// System.out.println("Snap shot generation simple test passed");
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Walking into a type, without explicitly doing so
|
||||
// *
|
||||
// * note: this currently fails.
|
||||
// *
|
||||
// * @param context2
|
||||
// * @
|
||||
// * @throws EOperationOutcome
|
||||
// */
|
||||
// private void testTypeWalk2() throws EOperationOutcome, Exception {
|
||||
// StructureDefinition focus = new StructureDefinition();
|
||||
// StructureDefinition base = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/Patient").copy();
|
||||
// focus.setUrl(Utilities.makeUuidUrn());
|
||||
// focus.setBaseDefinition(base.getUrl());
|
||||
// focus.setType(base.getType());
|
||||
// focus.setDerivation(TypeDerivationRule.CONSTRAINT);
|
||||
// ElementDefinition id = focus.getDifferential().addElement();
|
||||
// id.setPath("Patient.identifier.system");
|
||||
// id.setMustSupport(true);
|
||||
// List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
|
||||
// new ProfileUtilities(context, messages, null).generateSnapshot(base, focus, focus.getUrl(), "Simple Test" );
|
||||
//
|
||||
// // the derived should be 8 longer
|
||||
// boolean ok = base.getSnapshot().getElement().size() == focus.getSnapshot().getElement().size() - 8;
|
||||
// for (int i = 0; i < base.getSnapshot().getElement().size(); i++) {
|
||||
// if (ok) {
|
||||
// ElementDefinition b = base.getSnapshot().getElement().get(i);
|
||||
// ElementDefinition f = focus.getSnapshot().getElement().get(i <= 9 ? i : i + 8);
|
||||
// if (!f.hasBase() || !b.getPath().equals(f.getBase().getPath()))
|
||||
// ok = false;
|
||||
// else {
|
||||
// f.setBase(null);
|
||||
// if (f.getPath().equals("Patient.identifier")) {
|
||||
// ok = f.getMustSupport() && !b.getMustSupport();
|
||||
// if (ok) {
|
||||
// f.setMustSupportElement(null);
|
||||
// }
|
||||
// }
|
||||
// ok = Base.compareDeep(b, f, true);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (!ok) {
|
||||
// compareXml(base, focus);
|
||||
// throw new FHIRException("Snap shot generation simple test failed");
|
||||
// } else
|
||||
// System.out.println("Snap shot generation simple test passed");
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * we're going to slice Patient.identifier
|
||||
// */
|
||||
// private void testSlicingSimple() throws EOperationOutcome, Exception {
|
||||
//
|
||||
// StructureDefinition focus = new StructureDefinition();
|
||||
// StructureDefinition base = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/Patient").copy();
|
||||
// focus.setUrl(Utilities.makeUuidUrn());
|
||||
// focus.setBaseDefinition(base.getUrl());
|
||||
// focus.setType(base.getType());
|
||||
// focus.setDerivation(TypeDerivationRule.CONSTRAINT);
|
||||
//
|
||||
// // set the slice up
|
||||
// ElementDefinition id = focus.getDifferential().addElement();
|
||||
// id.setPath("Patient.identifier");
|
||||
// id.getSlicing().setOrdered(false).setRules(SlicingRules.OPEN).addDiscriminator().setPath("use").setType(DiscriminatorType.VALUE);
|
||||
//
|
||||
// // first slice:
|
||||
// id = focus.getDifferential().addElement();
|
||||
// id.setPath("Patient.identifier");
|
||||
// id.setSliceName("name1");
|
||||
// id = focus.getDifferential().addElement();
|
||||
// id.setPath("Patient.identifier.use");
|
||||
// id.setFixed(new CodeType("usual"));
|
||||
//
|
||||
// // second slice:
|
||||
// id = focus.getDifferential().addElement();
|
||||
// id.setPath("Patient.identifier");
|
||||
// id.setSliceName("name2");
|
||||
// id = focus.getDifferential().addElement();
|
||||
// id.setPath("Patient.identifier.use");
|
||||
// id.setFixed(new CodeType("official"));
|
||||
//
|
||||
//
|
||||
// List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
|
||||
// new ProfileUtilities(context, messages, null).generateSnapshot(base, focus, focus.getUrl(), "Simple Test" );
|
||||
//
|
||||
// // 18 different: identifier + 8 inner children * 2
|
||||
// boolean ok = base.getSnapshot().getElement().size() == focus.getSnapshot().getElement().size() - 18;
|
||||
// for (int i = 0; i < base.getSnapshot().getElement().size(); i++) {
|
||||
// if (ok) {
|
||||
// ElementDefinition b = base.getSnapshot().getElement().get(i);
|
||||
// ElementDefinition f = focus.getSnapshot().getElement().get(i <= 9 ? i : i + 18);
|
||||
// if (!f.hasBase() || !b.getPath().equals(f.getBase().getPath()))
|
||||
// ok = false;
|
||||
// else {
|
||||
// f.setBase(null);
|
||||
// if (f.getPath().equals("Patient.identifier")) {
|
||||
// ok = f.hasSlicing();
|
||||
// if (ok)
|
||||
// f.setSlicing(null);
|
||||
// }
|
||||
// ok = Base.compareDeep(b, f, true);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // now, check that the slices we skipped are correct:
|
||||
// for (int i = 10; i <= 18; i++) {
|
||||
// if (ok) {
|
||||
// ElementDefinition d1 = focus.getSnapshot().getElement().get(i);
|
||||
// ElementDefinition d2 = focus.getSnapshot().getElement().get(i+9);
|
||||
// if (d1.getPath().equals("Patient.identifier.use")) {
|
||||
// ok = d1.hasFixed() && d2.hasFixed() && !Base.compareDeep(d1.getFixed(), d2.getFixed(), true);
|
||||
// if (ok) {
|
||||
// d1.setFixed(null);
|
||||
// d2.setFixed(null);
|
||||
// }
|
||||
// }
|
||||
// if (d1.getPath().equals("Patient.identifier")) {
|
||||
// ok = d1.hasSliceName() && d2.hasSliceName() && !Base.compareDeep(d1.getSliceNameElement(), d2.getSliceNameElement(), true);
|
||||
// if (ok) {
|
||||
// d1.setSliceName(null);
|
||||
// d2.setSliceName(null);
|
||||
// }
|
||||
// }
|
||||
// ok = Base.compareDeep(d1, d2, true);
|
||||
// }
|
||||
// }
|
||||
// // for throughness, we could check against identifier too, but this is not done now.
|
||||
//
|
||||
// if (!ok) {
|
||||
// compareXml(base, focus);
|
||||
// throw new FHIRException("Snap shot generation slicing failed");
|
||||
// } else
|
||||
// System.out.println("Snap shot generation slicing passed");
|
||||
//
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * we're going to slice Patient.extension and refer to extension by profile
|
||||
// *
|
||||
// * implicit: whether to rely on implicit extension slicing
|
||||
// */
|
||||
// private void testSlicingExtension(boolean implicit) throws EOperationOutcome, Exception {
|
||||
//
|
||||
// StructureDefinition focus = new StructureDefinition();
|
||||
// StructureDefinition base = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/Patient").copy();
|
||||
// focus.setUrl(Utilities.makeUuidUrn());
|
||||
// focus.setBaseDefinition(base.getUrl());
|
||||
// focus.setType(base.getType());
|
||||
// focus.setDerivation(TypeDerivationRule.CONSTRAINT);
|
||||
//
|
||||
// // set the slice up
|
||||
// ElementDefinition id;
|
||||
// if (!implicit) {
|
||||
// id = focus.getDifferential().addElement();
|
||||
// id.setPath("Patient.extension");
|
||||
// id.getSlicing().setOrdered(false).setRules(SlicingRules.OPEN).addDiscriminator().setPath("url").setType(DiscriminatorType.VALUE);
|
||||
// id.setMax("3");
|
||||
// }
|
||||
// // first slice:
|
||||
// id = focus.getDifferential().addElement();
|
||||
// id.setPath("Patient.extension");
|
||||
// id.setSliceName("name1");
|
||||
// id.addType().setCode("Extension").setProfile("http://hl7.org/fhir/StructureDefinition/patient-birthTime");
|
||||
// id.setMin(1);
|
||||
//
|
||||
// // second slice:
|
||||
// id = focus.getDifferential().addElement();
|
||||
// id.setPath("Patient.extension");
|
||||
// id.setSliceName("name2");
|
||||
// id.addType().setCode("Extension").setProfile("http://hl7.org/fhir/StructureDefinition/patient-mothersMaidenName");
|
||||
//
|
||||
// List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
|
||||
// ProfileUtilities pu = new ProfileUtilities(context, messages, null);
|
||||
// pu.generateSnapshot(base, focus, focus.getUrl(), "Simple Test" );
|
||||
//
|
||||
// // 2 different: extension slices
|
||||
// boolean ok = base.getSnapshot().getElement().size() == focus.getSnapshot().getElement().size() - 2;
|
||||
// for (int i = 0; i < base.getSnapshot().getElement().size(); i++) {
|
||||
// if (ok) {
|
||||
// ElementDefinition b = base.getSnapshot().getElement().get(i);
|
||||
// ElementDefinition f = focus.getSnapshot().getElement().get(i <= 7 ? i : i + 2);
|
||||
// if (!f.hasBase() || !b.getPath().equals(f.getBase().getPath()))
|
||||
// ok = false;
|
||||
// else {
|
||||
// f.setBase(null);
|
||||
// if (f.getPath().equals("Patient.extension")) {
|
||||
// ok = f.hasSlicing() && (implicit || f.getMax().equals("3"));
|
||||
// if (ok) {
|
||||
// f.setSlicing(null);
|
||||
// f.setMaxElement(b.getMaxElement());
|
||||
// }
|
||||
// }
|
||||
// if (!f.getPath().equals("Patient.extension")) // no compare that because the definitions get overwritten
|
||||
// ok = Base.compareDeep(b, f, true);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // now, check that the slices we skipped are correct:
|
||||
// if (ok) {
|
||||
// ElementDefinition d1 = focus.getSnapshot().getElement().get(8);
|
||||
// ElementDefinition d2 = focus.getSnapshot().getElement().get(9);
|
||||
// ok = d1.hasType() && d1.getType().get(0).hasProfile() && d2.hasType() && d2.getType().get(0).hasProfile() && !Base.compareDeep(d1.getType(), d2.getType(), true) &&
|
||||
// d1.getMin() == 1 && d2.getMin() == 0 && d1.getMax().equals("1") && d2.getMax().equals("1");
|
||||
// if (ok) {
|
||||
// d1.getType().clear();
|
||||
// d2.getType().clear();
|
||||
// d1.setSliceName("x");
|
||||
// d2.setSliceName("x");
|
||||
// d1.setMin(0);
|
||||
// }
|
||||
// ok = Base.compareDeep(d1, d2, true);
|
||||
// // for throughness, we could check against extension too, but this is not done now.
|
||||
// }
|
||||
//
|
||||
// if (!ok) {
|
||||
// compareXml(base, focus);
|
||||
// throw new FHIRException("Snap shot generation slicing extensions simple ("+(implicit ? "implicit" : "not implicit")+") failed");
|
||||
// } else
|
||||
// System.out.println("Snap shot generation slicing extensions simple ("+(implicit ? "implicit" : "not implicit")+") passed");
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * we're going to slice Patient.extension and refer to extension by profile. one of the extensions is complex, and we're going to walk into
|
||||
// * it and make it must support
|
||||
// *
|
||||
// * implicit: whether to rely on implicit extension slicing
|
||||
// */
|
||||
// private void testSlicingExtensionComplex(boolean implicit) throws EOperationOutcome, Exception {
|
||||
//
|
||||
// StructureDefinition focus = new StructureDefinition();
|
||||
// StructureDefinition base = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/Patient").copy();
|
||||
// focus.setUrl(Utilities.makeUuidUrn());
|
||||
// focus.setBaseDefinition(base.getUrl());
|
||||
// focus.setType(base.getType());
|
||||
// focus.setDerivation(TypeDerivationRule.CONSTRAINT);
|
||||
//
|
||||
// // set the slice up
|
||||
// ElementDefinition id;
|
||||
// if (!implicit) {
|
||||
// id = focus.getDifferential().addElement();
|
||||
// id.setPath("Patient.extension");
|
||||
// id.getSlicing().setOrdered(false).setRules(SlicingRules.OPEN).addDiscriminator().setPath("url").setType(DiscriminatorType.VALUE);
|
||||
// }
|
||||
// // first slice - a simple one to get us going:
|
||||
// id = focus.getDifferential().addElement();
|
||||
// id.setPath("Patient.extension");
|
||||
// id.setSliceName("simple");
|
||||
// id.addType().setCode("Extension").setProfile("http://hl7.org/fhir/StructureDefinition/patient-birthTime");
|
||||
//
|
||||
// // second slice - the complex one
|
||||
// // we walk into this and fix properties on the inner extensions
|
||||
// id = focus.getDifferential().addElement();
|
||||
// id.setPath("Patient.extension");
|
||||
// id.setSliceName("complex");
|
||||
// id.addType().setCode("Extension").setProfile("http://hl7.org/fhir/StructureDefinition/patient-nationality");
|
||||
// if (!implicit) {
|
||||
// id = focus.getDifferential().addElement();
|
||||
// id.setPath("Patient.extension.extension");
|
||||
// id.getSlicing().setOrdered(false).setRules(SlicingRules.OPEN).addDiscriminator().setPath("url").setType(DiscriminatorType.VALUE);
|
||||
// }
|
||||
// id = focus.getDifferential().addElement();
|
||||
// id.setPath("Patient.extension.extension");
|
||||
// id.setSliceName("code");
|
||||
// id.setMustSupport(true);
|
||||
// id.addType().setCode("Extension").setProfile("http://hl7.org/fhir/StructureDefinition/patient-nationality#code");
|
||||
//
|
||||
// id = focus.getDifferential().addElement();
|
||||
// id.setPath("Patient.extension.extension");
|
||||
// id.setSliceName("period");
|
||||
// id.addType().setCode("Extension").setProfile("http://hl7.org/fhir/StructureDefinition/patient-nationality#period");
|
||||
// id.setMax("0"); // prohibit this one....
|
||||
//
|
||||
// List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
|
||||
// new ProfileUtilities(context, messages, null).generateSnapshot(base, focus, focus.getUrl(), "Simple Test" );
|
||||
//
|
||||
// // ok, there's going to 1 (simple) + complex: 1 + id + extnesion.slice + extension.code + (4 inside from that) + extension.period + (4 inside from that) + value + url = 16
|
||||
// boolean ok = base.getSnapshot().getElement().size() == focus.getSnapshot().getElement().size() - 16;
|
||||
//
|
||||
// // custom checks
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(7).getPath().equals("Patient.extension"), "element 7 (base) path");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(7).hasSlicing(), "element 7 slicing");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(8).getPath().equals("Patient.extension"), "element 8 (1st slice) path");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(8).getSliceName().equals("simple"), "element 8 (1st slice) name");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(8).getType().get(0).getProfile().equals("http://hl7.org/fhir/StructureDefinition/patient-birthTime"), "element 9 (2nd slice) profile name");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(9).getPath().equals("Patient.extension"), "element 9 (2nd slice) path");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(9).getSliceName().equals("complex"), "element 8 (1st slice) name");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(9).getType().get(0).getProfile().equals("http://hl7.org/fhir/StructureDefinition/patient-nationality"), "element 9 (2nd slice) profile name");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(10).getPath().equals("Patient.extension.id"), "element 10 (2nd slice).id path");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(11).getPath().equals("Patient.extension.extension"), "element 11 (2nd slice).extension path");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(12).getPath().equals("Patient.extension.extension"), "element 12 (2nd slice).extension path");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(12).getMustSupport(), "element 12 (2nd slice).extension must support");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(13).getPath().equals("Patient.extension.extension.id"), "element 13 (2nd slice).extension.id path");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(14).getPath().equals("Patient.extension.extension.extension"), "element 14 (2nd slice).extension.extension path");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(15).getPath().equals("Patient.extension.extension.url"), "element 15 (2nd slice).extension.url path");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(16).getPath().equals("Patient.extension.extension.valueCodeableConcept"), "element 16 (2nd slice).extension.valueCodeableConcept path");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(17).getPath().equals("Patient.extension.extension"), "element 17 (2nd slice).extension path");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(17).getMax().equals("0"), "element 17 (2nd slice).extension cardinality");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(18).getPath().equals("Patient.extension.extension.id"), "element 18 (2nd slice).extension.id path");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(19).getPath().equals("Patient.extension.extension.extension"), "element 19 (2nd slice).extension.extension path");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(20).getPath().equals("Patient.extension.extension.url"), "element 20 (2nd slice).extension.url path");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(21).getPath().equals("Patient.extension.extension.valuePeriod"), "element 21 (2nd slice).extension.valuePeriod path");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(22).getPath().equals("Patient.extension.url"), "element 22 (2nd slice).url path");
|
||||
// ok = ok && rule(focus.getSnapshot().getElement().get(23).getPath().equals("Patient.extension.value[x]"), "element 23 (2nd slice).url path");
|
||||
//
|
||||
// for (int i = 0; i < base.getSnapshot().getElement().size(); i++) {
|
||||
// if (ok) {
|
||||
// ElementDefinition b = base.getSnapshot().getElement().get(i);
|
||||
// ElementDefinition f = focus.getSnapshot().getElement().get(i <= 7 ? i : i + 16);
|
||||
// if (!f.hasBase() || !b.getPath().equals(f.getBase().getPath()))
|
||||
// ok = false;
|
||||
// else {
|
||||
// f.setBase(null);
|
||||
// if (f.getPath().equals("Patient.extension")) {
|
||||
// ok = f.hasSlicing();
|
||||
// if (ok)
|
||||
// f.setSlicing(null);
|
||||
// }
|
||||
// if (!f.getPath().equals("Patient.extension")) // no compare that because the definitions get overwritten
|
||||
// ok = Base.compareDeep(b, f, true);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (!ok) {
|
||||
// compareXml(base, focus);
|
||||
// throw new FHIRException("Snap shot generation slicing extensions complex ("+(implicit ? "implicit" : "not implicit")+") failed");
|
||||
// } else
|
||||
// System.out.println("Snap shot generation slicing extensions complex ("+(implicit ? "implicit" : "not implicit")+") passed");
|
||||
// }
|
||||
//
|
||||
// private void testSlicingTask8742() throws EOperationOutcome, Exception {
|
||||
// StructureDefinition focus = new StructureDefinition();
|
||||
// StructureDefinition base = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/Organization").copy();
|
||||
// focus.setUrl(Utilities.makeUuidUrn());
|
||||
// focus.setBaseDefinition(base.getUrl());
|
||||
// focus.setType(base.getType());
|
||||
// focus.setDerivation(TypeDerivationRule.CONSTRAINT);
|
||||
//
|
||||
// ElementDefinition id = focus.getDifferential().addElement();
|
||||
// id.setPath("Organization.address");
|
||||
// id.setMin(1);
|
||||
// id.setMax("1");
|
||||
// id.setMustSupport(true);
|
||||
//
|
||||
// id = focus.getDifferential().addElement();
|
||||
// id.setPath("Organization.address.extension");
|
||||
// id.setSliceName("USLabCountycodes");
|
||||
// id.getSlicing().setOrdered(false).setRules(SlicingRules.OPEN).addDiscriminator().setPath("url").setType(DiscriminatorType.VALUE);
|
||||
// id.setShort("County/Parish FIPS codes");
|
||||
// id.setDefinition("County/Parish FIPS codes.");
|
||||
// id.setRequirements("County/Parish Code SHALL use FIPS 6-4 ( INCITS 31:2009).");
|
||||
// id.setMin(0);
|
||||
// id.setMax("1");
|
||||
// id.addType().setCode("Extension").setProfile("http://hl7.org/fhir/StructureDefinition/us-core-county");
|
||||
// id.setMustSupport(true);
|
||||
// id.getBinding().setStrength(BindingStrength.REQUIRED).setDescription("FIPS codes for US counties and county equivalent entities.").setValueSet(new Reference().setReference("http://hl7.org/fhir/ValueSet/fips-county"));
|
||||
// List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
|
||||
//
|
||||
// new ProfileUtilities(context, messages, null).generateSnapshot(base, focus, focus.getUrl(), "Simple Test" );
|
||||
//
|
||||
// // 14 for address with one sliced extension
|
||||
// boolean ok = base.getSnapshot().getElement().size() == focus.getSnapshot().getElement().size() - 13;
|
||||
//
|
||||
// if (!ok) {
|
||||
// compareXml(base, focus);
|
||||
// throw new FHIRException("Snap shot generation test 8742 failed");
|
||||
// } else
|
||||
// System.out.println("Snap shot generation test 8742 passed");
|
||||
// }
|
||||
//
|
||||
//
|
||||
// private boolean rule(boolean ok, String message) {
|
||||
// if (!ok)
|
||||
// System.out.println("Test failed: " + message);
|
||||
// return ok;
|
||||
// }
|
||||
//
|
||||
|
||||
private void compareXml(StructureDefinition base, StructureDefinition focus) throws FileNotFoundException, IOException {
|
||||
base.setText(null);
|
||||
focus.setText(null);
|
||||
base.setDifferential(null);
|
||||
// focus.setDifferential(null);
|
||||
String f1 = Utilities.path("c:", "temp", "base.xml");
|
||||
String f2 = Utilities.path("c:", "temp", "derived.xml");
|
||||
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(f1), base);;
|
||||
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(f2), focus);;
|
||||
String diff = Utilities.path(System.getenv("ProgramFiles(X86)"), "WinMerge", "WinMergeU.exe");
|
||||
List<String> command = new ArrayList<String>();
|
||||
command.add("\"" + diff + "\" \"" + f1 + "\" \"" + f2 + "\"");
|
||||
|
||||
ProcessBuilder builder = new ProcessBuilder(command);
|
||||
builder.directory(new CSFile("c:\\temp"));
|
||||
builder.start();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package org.hl7.fhir.r4.test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.hl7.fhir.r4.context.IWorkerContext;
|
||||
import org.hl7.fhir.r4.context.SimpleWorkerContext;
|
||||
import org.hl7.fhir.r4.formats.IParser.OutputStyle;
|
||||
import org.hl7.fhir.r4.formats.XmlParser;
|
||||
import org.hl7.fhir.r4.model.DomainResource;
|
||||
import org.hl7.fhir.r4.model.Resource;
|
||||
import org.hl7.fhir.r4.test.support.TestingUtilities;
|
||||
import org.hl7.fhir.r4.utils.EOperationOutcome;
|
||||
import org.hl7.fhir.r4.utils.NarrativeGenerator;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ResourceRoundTripTests {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws FileNotFoundException, IOException, FHIRException, EOperationOutcome {
|
||||
if (TestingUtilities.context == null)
|
||||
TestingUtilities.context = SimpleWorkerContext.fromPack(Utilities.path(TestingUtilities.home(), "publish", "definitions.xml.zip"));
|
||||
Resource res = new XmlParser().parse(new FileInputStream(Utilities.path(TestingUtilities.home(), "tests", "resources", "unicode.xml")));
|
||||
new NarrativeGenerator("", "", TestingUtilities.context).generate((DomainResource) res);
|
||||
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(TestingUtilities.home(), "tests", "resources","unicode.out.xml")), res);
|
||||
}
|
||||
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
package org.hl7.fhir.r4.test;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.hl7.fhir.r4.conformance.ShExGenerator;
|
||||
import org.hl7.fhir.r4.conformance.ShExGenerator.HTMLLinkPolicy;
|
||||
import org.hl7.fhir.r4.context.SimpleWorkerContext;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||
import org.hl7.fhir.r4.test.support.TestingUtilities;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ShexGeneratorTests {
|
||||
|
||||
private void doTest(String name) throws FileNotFoundException, IOException, FHIRException {
|
||||
String workingDirectory = "C:\\work\\org.hl7.fhir\\build\\publish"; // FileSystems.getDefault().getPath(System.getProperty("user.dir"), "data").toString();
|
||||
// String workingDirectory = FileSystems.getDefault().getPath(System.getProperty("user.dir"), "..", "..", "..", "publish").toString();
|
||||
if (TestingUtilities.context == null) {
|
||||
// For the time being, put the validation entry in org/hl7/fhir/r4/data
|
||||
Path path = FileSystems.getDefault().getPath(workingDirectory, "definitions.xml.zip");
|
||||
TestingUtilities.context = SimpleWorkerContext.fromPack(path.toString());
|
||||
}
|
||||
StructureDefinition sd = TestingUtilities.context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/"+name);
|
||||
if(sd == null) {
|
||||
throw new FHIRException("StructuredDefinition for " + name + "was null");
|
||||
}
|
||||
Path outPath = FileSystems.getDefault().getPath(workingDirectory, name.toLowerCase()+".shex");
|
||||
TextFile.stringToFile(new ShExGenerator(TestingUtilities.context).generate(HTMLLinkPolicy.NONE, sd), outPath.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testId() throws FHIRException, IOException {
|
||||
doTest("id");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUri() throws FHIRException, IOException {
|
||||
doTest("uri");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testObservation() throws FHIRException, IOException {
|
||||
doTest("Observation");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRef() throws FHIRException, IOException {
|
||||
doTest("Reference");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAccount() throws FHIRException, IOException {
|
||||
doTest("Account");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMedicationOrder() throws FHIRException, IOException {
|
||||
doTest("MedicationOrder");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllergyIntolerance() throws FHIRException, IOException {
|
||||
doTest("AllergyIntolerance");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCoding() throws FHIRException, IOException {
|
||||
doTest("Coding");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTiming() throws FHIRException, IOException {
|
||||
doTest("Timing");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSignature() throws FHIRException, IOException {
|
||||
doTest("Signature");
|
||||
}
|
||||
}
|
@ -1,338 +0,0 @@
|
||||
package org.hl7.fhir.r4.test;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.hl7.fhir.r4.conformance.ProfileUtilities;
|
||||
import org.hl7.fhir.r4.context.SimpleWorkerContext;
|
||||
import org.hl7.fhir.r4.formats.IParser.OutputStyle;
|
||||
import org.hl7.fhir.r4.formats.XmlParser;
|
||||
import org.hl7.fhir.r4.model.Base;
|
||||
import org.hl7.fhir.r4.model.BooleanType;
|
||||
import org.hl7.fhir.r4.model.Coding;
|
||||
import org.hl7.fhir.r4.model.ExpressionNode;
|
||||
import org.hl7.fhir.r4.model.MetadataResource;
|
||||
import org.hl7.fhir.r4.model.ExpressionNode.CollectionStatus;
|
||||
import org.hl7.fhir.r4.model.PrimitiveType;
|
||||
import org.hl7.fhir.r4.model.Resource;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||
import org.hl7.fhir.r4.model.TestScript;
|
||||
import org.hl7.fhir.r4.model.TestScript.SetupActionAssertComponent;
|
||||
import org.hl7.fhir.r4.model.TestScript.SetupActionComponent;
|
||||
import org.hl7.fhir.r4.model.TestScript.SetupActionOperationComponent;
|
||||
import org.hl7.fhir.r4.model.TestScript.TestActionComponent;
|
||||
import org.hl7.fhir.r4.model.TestScript.TestScriptFixtureComponent;
|
||||
import org.hl7.fhir.r4.model.TestScript.TestScriptTestComponent;
|
||||
import org.hl7.fhir.r4.model.TypeDetails;
|
||||
import org.hl7.fhir.r4.test.support.TestingUtilities;
|
||||
import org.hl7.fhir.r4.utils.CodingUtilities;
|
||||
import org.hl7.fhir.r4.utils.FHIRPathEngine;
|
||||
import org.hl7.fhir.r4.utils.FHIRPathEngine.IEvaluationContext;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.exceptions.PathEngineException;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.xml.XMLUtil;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import junit.framework.Assert;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class SnapShotGenerationTests {
|
||||
|
||||
private static class SnapShotGenerationTestsContext implements IEvaluationContext {
|
||||
private Map<String, Resource> fixtures;
|
||||
private Map<String, StructureDefinition> snapshots = new HashMap<String, StructureDefinition>();
|
||||
public TestScript tests;
|
||||
|
||||
public void checkTestsDetails() {
|
||||
if (!"http://hl7.org/fhir/tests/snapshotgeneration".equals(tests.getUrl()))
|
||||
throw new Error("Wrong URL on test script");
|
||||
if (!tests.getSetup().isEmpty())
|
||||
throw new Error("Setup is not supported");
|
||||
if (!tests.getTeardown().isEmpty())
|
||||
throw new Error("Teardown is not supported");
|
||||
Set<String> ids = new HashSet<String>();
|
||||
Set<String> urls = new HashSet<String>();
|
||||
for (Resource r : tests.getContained()) {
|
||||
if (ids.contains(r.getId()))
|
||||
throw new Error("Unsupported: duplicate contained resource on fixture id "+r.getId());
|
||||
ids.add(r.getId());
|
||||
if (r instanceof MetadataResource) {
|
||||
MetadataResource md = (MetadataResource) r;
|
||||
if (urls.contains(md.getUrl()))
|
||||
throw new Error("Unsupported: duplicate canonical url "+md.getUrl()+" on fixture id "+r.getId());
|
||||
urls.add(md.getUrl());
|
||||
}
|
||||
}
|
||||
for (TestScriptFixtureComponent r : tests.getFixture()) {
|
||||
if (ids.contains(r.getId()))
|
||||
throw new Error("Unsupported: duplicate contained resource or fixture id "+r.getId());
|
||||
ids.add(r.getId());
|
||||
}
|
||||
Set<String> names = new HashSet<String>();
|
||||
for (TestScriptTestComponent test : tests.getTest()) {
|
||||
if (names.contains(test.getName()))
|
||||
throw new Error("Unsupported: duplicate name "+test.getName());
|
||||
names.add(test.getName());
|
||||
if (test.getAction().size() < 2)
|
||||
throw new Error("Unsupported: multiple actions required");
|
||||
if (!test.getActionFirstRep().hasOperation())
|
||||
throw new Error("Unsupported: first action must be an operation");
|
||||
for (int i = 0; i < test.getAction().size(); i++) {
|
||||
// if (!test.getAction().get(i).hasAssert())
|
||||
// throw new Error("Unsupported: following actions must be an asserts");
|
||||
TestActionComponent action = test.getAction().get(i);
|
||||
if (action.hasOperation()) {
|
||||
SetupActionOperationComponent op = test.getActionFirstRep().getOperation();
|
||||
if (!CodingUtilities.matches(op.getType(), "http://hl7.org/fhir/testscript-operation-codes", "snapshot")
|
||||
&& !CodingUtilities.matches(op.getType(), "http://hl7.org/fhir/testscript-operation-codes", "sortDifferential"))
|
||||
throw new Error("Unsupported action operation type "+CodingUtilities.present(op.getType()));
|
||||
if (!"StructureDefinition".equals(op.getResource()))
|
||||
throw new Error("Unsupported action operation resource "+op.getResource());
|
||||
if (!op.hasResponseId())
|
||||
throw new Error("Unsupported action operation: no response id");
|
||||
if (!op.hasSourceId())
|
||||
throw new Error("Unsupported action operation: no source id");
|
||||
if (!hasSource(op.getSourceId()))
|
||||
throw new Error("Unsupported action operation: source id could not be resolved");
|
||||
} else if (action.hasAssert()) {
|
||||
SetupActionAssertComponent a = action.getAssert();
|
||||
if (!a.hasLabel())
|
||||
throw new Error("Unsupported: actions must have a label");
|
||||
if (!a.hasDescription())
|
||||
throw new Error("Unsupported: actions must have a description");
|
||||
if (!a.hasExpression())
|
||||
throw new Error("Unsupported: actions must have an expression");
|
||||
} else {
|
||||
throw new Error("Unsupported: Unrecognized action type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasSource(String sourceId) {
|
||||
for (TestScriptFixtureComponent ds : tests.getFixture()) {
|
||||
if (sourceId.equals(ds.getId()))
|
||||
return true;
|
||||
}
|
||||
for (Resource r : tests.getContained()) {
|
||||
if (sourceId.equals(r.getId()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Resource fetchFixture(String id) {
|
||||
if (fixtures.containsKey(id))
|
||||
return fixtures.get(id);
|
||||
|
||||
for (TestScriptFixtureComponent ds : tests.getFixture()) {
|
||||
if (id.equals(ds.getId()))
|
||||
throw new Error("not done yet");
|
||||
}
|
||||
for (Resource r : tests.getContained()) {
|
||||
if (id.equals(r.getId()))
|
||||
return r;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// FHIRPath methods
|
||||
@Override
|
||||
public Base resolveConstant(Object appContext, String name) throws PathEngineException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDetails resolveConstantType(Object appContext, String name) throws PathEngineException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean log(String argument, List<Base> focus) {
|
||||
System.out.println(argument+": "+fp.convertToString(focus));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionDetails resolveFunction(String functionName) {
|
||||
if ("fixture".equals(functionName))
|
||||
return new FunctionDetails("Access a fixture defined in the testing context", 0, 1);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDetails checkFunction(Object appContext, String functionName, List<TypeDetails> parameters) throws PathEngineException {
|
||||
if ("fixture".equals(functionName))
|
||||
return new TypeDetails(CollectionStatus.SINGLETON, TestingUtilities.context.getResourceNamesAsSet());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Base> executeFunction(Object appContext, String functionName, List<List<Base>> parameters) {
|
||||
if ("fixture".equals(functionName)) {
|
||||
String id = fp.convertToString(parameters.get(0));
|
||||
Resource res = fetchFixture(id);
|
||||
if (res != null) {
|
||||
List<Base> list = new ArrayList<Base>();
|
||||
list.add(res);
|
||||
return list;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Base resolveReference(Object appContext, String url) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static FHIRPathEngine fp;
|
||||
|
||||
@Parameters(name = "{index}: file {0}")
|
||||
public static Iterable<Object[]> data() throws ParserConfigurationException, IOException, FHIRFormatError {
|
||||
SnapShotGenerationTestsContext context = new SnapShotGenerationTestsContext();
|
||||
context.tests = (TestScript) new XmlParser().parse(new FileInputStream(Utilities.path(TestingUtilities.home(), "tests", "resources", "snapshot-generation-tests.xml")));
|
||||
|
||||
context.checkTestsDetails();
|
||||
|
||||
List<Object[]> objects = new ArrayList<Object[]>(context.tests.getTest().size());
|
||||
|
||||
for (TestScriptTestComponent e : context.tests.getTest()) {
|
||||
objects.add(new Object[] { e.getName(), e, context });
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
|
||||
|
||||
private final TestScriptTestComponent test;
|
||||
private final String name;
|
||||
private SnapShotGenerationTestsContext context;
|
||||
|
||||
public SnapShotGenerationTests(String name, TestScriptTestComponent e, SnapShotGenerationTestsContext context) {
|
||||
this.name = name;
|
||||
this.test = e;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void test() throws FileNotFoundException, IOException, FHIRException, org.hl7.fhir.exceptions.FHIRException {
|
||||
if (TestingUtilities.context == null)
|
||||
TestingUtilities.context = SimpleWorkerContext.fromPack(Utilities.path(TestingUtilities.home(), "publish", "definitions.xml.zip"));
|
||||
if (fp == null)
|
||||
fp = new FHIRPathEngine(TestingUtilities.context);
|
||||
fp.setHostServices(context);
|
||||
|
||||
resolveFixtures();
|
||||
|
||||
for (int i = 0; i < test.getAction().size(); i++) {
|
||||
TestActionComponent action = test.getAction().get(i);
|
||||
if (action.hasOperation()) {
|
||||
SetupActionOperationComponent op = action.getOperation();
|
||||
Coding opType = op.getType();
|
||||
if (opType.getSystem().equals("http://hl7.org/fhir/testscript-operation-codes") && opType.getCode().equals("snapshot")) {
|
||||
StructureDefinition source = (StructureDefinition) context.fetchFixture(op.getSourceId());
|
||||
StructureDefinition base = getSD(source.getBaseDefinition());
|
||||
StructureDefinition output = source.copy();
|
||||
ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context, null, null);
|
||||
pu.setIds(source, false);
|
||||
if ("sort=true".equals(op.getParams())) {
|
||||
List<String> errors = new ArrayList<String>();
|
||||
pu.sortDifferential(base, output, source.getName(), errors);
|
||||
if (errors.size() > 0)
|
||||
throw new FHIRException("Sort failed: "+errors.toString());
|
||||
}
|
||||
pu.generateSnapshot(base, output, source.getUrl(), source.getName());
|
||||
context.fixtures.put(op.getResponseId(), output);
|
||||
context.snapshots.put(output.getUrl(), output);
|
||||
|
||||
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(System.getProperty("java.io.tmpdir"), op.getResponseId()+".xml")), output);
|
||||
|
||||
} else if (opType.getSystem().equals("http://hl7.org/fhir/testscript-operation-codes") && opType.getCode().equals("sortDifferential")) {
|
||||
StructureDefinition source = (StructureDefinition) context.fetchFixture(op.getSourceId());
|
||||
StructureDefinition base = getSD(source.getBaseDefinition());
|
||||
StructureDefinition output = source.copy();
|
||||
ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context, null, null);
|
||||
pu.setIds(source, false);
|
||||
List<String> errors = new ArrayList<String>();
|
||||
pu.sortDifferential(base, output, output.getUrl(), errors);
|
||||
if (!errors.isEmpty())
|
||||
throw new FHIRException(errors.get(0));
|
||||
context.fixtures.put(op.getResponseId(), output);
|
||||
context.snapshots.put(output.getUrl(), output);
|
||||
|
||||
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(System.getProperty("java.io.tmpdir"), op.getResponseId()+".xml")), output);
|
||||
|
||||
} else {
|
||||
throw new Error("Unsupported operation: " + opType.getSystem() + " : " + opType.getCode());
|
||||
}
|
||||
} else if (action.hasAssert()) {
|
||||
SetupActionAssertComponent a = action.getAssert();
|
||||
Assert.assertTrue(a.getLabel()+": "+a.getDescription(), fp.evaluateToBoolean(new StructureDefinition(), new StructureDefinition(), a.getExpression()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private StructureDefinition getSD(String url) throws DefinitionException, FHIRException {
|
||||
StructureDefinition sd = TestingUtilities.context.fetchResource(StructureDefinition.class, url);
|
||||
if (sd == null)
|
||||
sd = context.snapshots.get(url);
|
||||
if (sd == null)
|
||||
sd = findContainedProfile(url);
|
||||
return sd;
|
||||
}
|
||||
|
||||
private StructureDefinition findContainedProfile(String url) throws DefinitionException, FHIRException {
|
||||
for (Resource r : context.tests.getContained()) {
|
||||
if (r instanceof StructureDefinition) {
|
||||
StructureDefinition sd = (StructureDefinition) r;
|
||||
if (sd.getUrl().equals(url)) {
|
||||
StructureDefinition p = sd.copy();
|
||||
ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context, null, null);
|
||||
pu.setIds(p, false);
|
||||
List<String> errors = new ArrayList<String>();
|
||||
pu.sortDifferential(getSD(p.getBaseDefinition()), p, url, errors);
|
||||
if (!errors.isEmpty())
|
||||
throw new FHIRException(errors.get(0));
|
||||
pu.generateSnapshot(getSD(p.getBaseDefinition()), p, p.getUrl(), p.getName());
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void resolveFixtures() {
|
||||
if (context.fixtures == null) {
|
||||
context.fixtures = new HashMap<String, Resource>();
|
||||
for (TestScriptFixtureComponent fd : context.tests.getFixture()) {
|
||||
Resource r = TestingUtilities.context.fetchResource(Resource.class, fd.getResource().getReference());
|
||||
context.fixtures.put(fd.getId(), r);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,31 +1,8 @@
|
||||
package ca.uhn.fhir.to;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.*;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringEscapeUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestComponent;
|
||||
import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestResourceComponent;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IDomainResource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.thymeleaf.TemplateEngine;
|
||||
|
||||
import ca.uhn.fhir.context.*;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.ExtensionDt;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
@ -36,6 +13,31 @@ import ca.uhn.fhir.rest.client.api.*;
|
||||
import ca.uhn.fhir.rest.client.impl.GenericClient;
|
||||
import ca.uhn.fhir.to.model.HomeRequest;
|
||||
import ca.uhn.fhir.util.ExtensionConstants;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringEscapeUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.hl7.fhir.dstu3.model.CapabilityStatement;
|
||||
import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestComponent;
|
||||
import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestResourceComponent;
|
||||
import org.hl7.fhir.dstu3.model.DecimalType;
|
||||
import org.hl7.fhir.dstu3.model.Extension;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IDomainResource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.thymeleaf.TemplateEngine;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.*;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
|
||||
public class BaseController {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseController.class);
|
||||
@ -285,7 +287,7 @@ public class BaseController {
|
||||
ourLog.warn("Failed to invoke server", e);
|
||||
|
||||
if (e != null) {
|
||||
theModel.put("errorMsg", "Error: " + e.getMessage());
|
||||
theModel.put("errorMsg", toDisplayError("Error: " + e.getMessage(), e));
|
||||
}
|
||||
|
||||
return returnsResource;
|
||||
@ -313,8 +315,8 @@ public class BaseController {
|
||||
try {
|
||||
conformance = (ca.uhn.fhir.model.dstu2.resource.Conformance) client.conformance();
|
||||
} catch (Exception e) {
|
||||
ourLog.warn("Failed to load conformance statement", e);
|
||||
theModel.put("errorMsg", "Failed to load conformance statement, error was: " + e.toString());
|
||||
ourLog.warn("Failed to load conformance statement, error was: {}", e.toString());
|
||||
theModel.put("errorMsg", toDisplayError("Failed to load conformance statement, error was: " + e.toString(), e));
|
||||
conformance = new ca.uhn.fhir.model.dstu2.resource.Conformance();
|
||||
}
|
||||
|
||||
@ -373,8 +375,8 @@ public class BaseController {
|
||||
try {
|
||||
capabilityStatement = client.fetchConformance().ofType(org.hl7.fhir.dstu3.model.CapabilityStatement.class).execute();
|
||||
} catch (Exception ex) {
|
||||
ourLog.warn("Failed to load conformance statement", ex);
|
||||
theModel.put("errorMsg", "Failed to load conformance statement, error was: " + ex.toString());
|
||||
ourLog.warn("Failed to load conformance statement, error was: {}", ex.toString());
|
||||
theModel.put("errorMsg", toDisplayError("Failed to load conformance statement, error was: " + ex.toString(), ex));
|
||||
}
|
||||
|
||||
theModel.put("jsonEncodedConf", getContext(theRequest).newJsonParser().encodeResourceToString(capabilityStatement));
|
||||
@ -602,7 +604,7 @@ public class BaseController {
|
||||
|
||||
} catch (Exception e) {
|
||||
ourLog.error("Failure during processing", e);
|
||||
theModelMap.put("errorMsg", "Error during processing: " + e.getMessage());
|
||||
theModelMap.put("errorMsg", toDisplayError("Error during processing: " + e.getMessage(), e));
|
||||
}
|
||||
|
||||
}
|
||||
@ -679,4 +681,16 @@ public class BaseController {
|
||||
BUNDLE, NONE, RESOURCE, TAGLIST
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* A hook to be overridden by subclasses. The overriding method can modify the error message
|
||||
* based on its content and/or the related exception.
|
||||
*
|
||||
* @param theErrorMsg The original error message to be displayed to the user.
|
||||
* @param theException The exception that occurred. May be null.
|
||||
* @return The modified error message to be displayed to the user.
|
||||
*/
|
||||
protected String toDisplayError(String theErrorMsg, Exception theException) {
|
||||
return theErrorMsg;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
package ca.uhn.fhir.to;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
import static org.apache.commons.lang3.StringUtils.defaultIfEmpty;
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
@ -63,15 +66,15 @@ public class Controller extends BaseController {
|
||||
Class<? extends IBaseConformance> type;
|
||||
switch (getContext(theRequest).getVersion().getVersion()) {
|
||||
default:
|
||||
case DSTU1:
|
||||
type = Conformance.class;
|
||||
break;
|
||||
case DSTU2:
|
||||
type = ca.uhn.fhir.model.dstu2.resource.Conformance.class;
|
||||
break;
|
||||
case DSTU3:
|
||||
type = org.hl7.fhir.dstu3.model.CapabilityStatement.class;
|
||||
break;
|
||||
case R4:
|
||||
type = org.hl7.fhir.r4.model.CapabilityStatement.class;
|
||||
break;
|
||||
}
|
||||
client.fetchConformance().ofType(type).execute();
|
||||
} catch (Exception e) {
|
||||
@ -103,13 +106,13 @@ public class Controller extends BaseController {
|
||||
try {
|
||||
def = getResourceType(theRequest, theReq);
|
||||
} catch (ServletException e) {
|
||||
theModel.put("errorMsg", e.toString());
|
||||
theModel.put("errorMsg", toDisplayError(e.toString(), e));
|
||||
return "resource";
|
||||
}
|
||||
|
||||
String id = StringUtils.defaultString(theReq.getParameter("resource-delete-id"));
|
||||
if (StringUtils.isBlank(id)) {
|
||||
theModel.put("errorMsg", "No ID specified");
|
||||
theModel.put("errorMsg", toDisplayError("No ID specified", null));
|
||||
return "resource";
|
||||
}
|
||||
|
||||
@ -148,7 +151,7 @@ public class Controller extends BaseController {
|
||||
try {
|
||||
def = getResourceType(theRequest, theReq);
|
||||
} catch (ServletException e) {
|
||||
theModel.put("errorMsg", e.toString());
|
||||
theModel.put("errorMsg", toDisplayError(e.toString(), e));
|
||||
return "resource";
|
||||
}
|
||||
|
||||
@ -212,11 +215,11 @@ public class Controller extends BaseController {
|
||||
if (myConfig.isRefuseToFetchThirdPartyUrls()) {
|
||||
if (!url.startsWith(theModel.get("base").toString())) {
|
||||
ourLog.warn(logPrefix(theModel) + "Refusing to load page URL: {}", url);
|
||||
theModel.put("errorMsg", "Invalid page URL: " + url);
|
||||
theModel.put("errorMsg", toDisplayError("Invalid page URL: " + url, null));
|
||||
return "result";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
url = url.replace("&", "&");
|
||||
|
||||
ResultType returnsResource = ResultType.BUNDLE;
|
||||
@ -224,13 +227,9 @@ public class Controller extends BaseController {
|
||||
long start = System.currentTimeMillis();
|
||||
try {
|
||||
ourLog.info(logPrefix(theModel) + "Loading paging URL: {}", url);
|
||||
if (context.getVersion().getVersion() == FhirVersionEnum.DSTU1) {
|
||||
client.loadPage().byUrl(url).andReturnDstu1Bundle().execute();
|
||||
} else {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends IBaseBundle> bundleType = (Class<? extends IBaseBundle>) context.getResourceDefinition("Bundle").getImplementingClass();
|
||||
client.loadPage().byUrl(url).andReturnBundle(bundleType).execute();
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends IBaseBundle> bundleType = (Class<? extends IBaseBundle>) context.getResourceDefinition("Bundle").getImplementingClass();
|
||||
client.loadPage().byUrl(url).andReturnBundle(bundleType).execute();
|
||||
} catch (Exception e) {
|
||||
returnsResource = handleClientException(client, e, theModel);
|
||||
}
|
||||
@ -254,12 +253,12 @@ public class Controller extends BaseController {
|
||||
try {
|
||||
def = getResourceType(theRequest, theReq);
|
||||
} catch (ServletException e) {
|
||||
theModel.put("errorMsg", e.toString());
|
||||
theModel.put("errorMsg", toDisplayError(e.toString(), e));
|
||||
return "resource";
|
||||
}
|
||||
String id = StringUtils.defaultString(theReq.getParameter("id"));
|
||||
if (StringUtils.isBlank(id)) {
|
||||
theModel.put("errorMsg", "No ID specified");
|
||||
theModel.put("errorMsg", toDisplayError("No ID specified", null));
|
||||
return "resource";
|
||||
}
|
||||
ResultType returnsResource = ResultType.RESOURCE;
|
||||
@ -315,13 +314,16 @@ public class Controller extends BaseController {
|
||||
case DSTU3:
|
||||
haveSearchParams = extractSearchParamsDstu3CapabilityStatement(conformance, resourceName, includes, revIncludes, sortParams, haveSearchParams, queryIncludes);
|
||||
break;
|
||||
case R4:
|
||||
haveSearchParams = extractSearchParamsR4CapabilityStatement(conformance, resourceName, includes, revIncludes, sortParams, haveSearchParams, queryIncludes);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown FHIR version: " + theRequest.getFhirVersion(myConfig));
|
||||
}
|
||||
|
||||
theModel.put("includes", includes);
|
||||
theModel.put("revincludes", revIncludes);
|
||||
theModel.put("queries", Collections.emptyList()); //TODO: remove this, it does nothing
|
||||
theModel.put("queries", Collections.emptyList()); // TODO: remove this, it does nothing
|
||||
theModel.put("haveSearchParams", haveSearchParams);
|
||||
theModel.put("queryIncludes", queryIncludes);
|
||||
theModel.put("sortParams", sortParams);
|
||||
@ -362,7 +364,7 @@ public class Controller extends BaseController {
|
||||
try {
|
||||
query = search.forResource((Class<? extends IBaseResource>) getResourceType(theRequest, theReq).getImplementingClass());
|
||||
} catch (ServletException e) {
|
||||
theModel.put("errorMsg", e.toString());
|
||||
theModel.put("errorMsg", toDisplayError(e.toString(), e));
|
||||
return "resource";
|
||||
}
|
||||
clientCodeJsonWriter.name("resource");
|
||||
@ -434,7 +436,7 @@ public class Controller extends BaseController {
|
||||
String limit = theReq.getParameter("resource-search-limit");
|
||||
if (isNotBlank(limit)) {
|
||||
if (!limit.matches("[0-9]+")) {
|
||||
theModel.put("errorMsg", "Search limit must be a numeric value.");
|
||||
theModel.put("errorMsg", toDisplayError("Search limit must be a numeric value.", null));
|
||||
return "resource";
|
||||
}
|
||||
int limitInt = Integer.parseInt(limit);
|
||||
@ -463,9 +465,7 @@ public class Controller extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
if (client.getFhirContext().getVersion().getVersion() != FhirVersionEnum.DSTU1) {
|
||||
query.returnBundle(client.getFhirContext().getResourceDefinition("Bundle").getImplementingClass());
|
||||
}
|
||||
query.returnBundle(client.getFhirContext().getResourceDefinition("Bundle").getImplementingClass());
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
ResultType returnsResource;
|
||||
@ -505,12 +505,13 @@ public class Controller extends BaseController {
|
||||
} else if (body.startsWith("<")) {
|
||||
// XML content
|
||||
} else {
|
||||
theModel.put("errorMsg", "Message body does not appear to be a valid FHIR resource instance document. Body should start with '<' (for XML encoding) or '{' (for JSON encoding).");
|
||||
theModel.put("errorMsg",
|
||||
toDisplayError("Message body does not appear to be a valid FHIR resource instance document. Body should start with '<' (for XML encoding) or '{' (for JSON encoding).", null));
|
||||
return "home";
|
||||
}
|
||||
} catch (DataFormatException e) {
|
||||
ourLog.warn("Failed to parse bundle", e);
|
||||
theModel.put("errorMsg", "Failed to parse transaction bundle body. Error was: " + e.getMessage());
|
||||
theModel.put("errorMsg", toDisplayError("Failed to parse transaction bundle body. Error was: " + e.getMessage(), e));
|
||||
return "home";
|
||||
}
|
||||
|
||||
@ -558,7 +559,7 @@ public class Controller extends BaseController {
|
||||
|
||||
String body = validate ? theReq.getParameter("resource-validate-body") : theReq.getParameter("resource-create-body");
|
||||
if (isBlank(body)) {
|
||||
theModel.put("errorMsg", "No message body specified");
|
||||
theModel.put("errorMsg", toDisplayError("No message body specified", null));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -573,12 +574,13 @@ public class Controller extends BaseController {
|
||||
resource = getContext(theRequest).newXmlParser().parseResource(type, body);
|
||||
client.setEncoding(EncodingEnum.XML);
|
||||
} else {
|
||||
theModel.put("errorMsg", "Message body does not appear to be a valid FHIR resource instance document. Body should start with '<' (for XML encoding) or '{' (for JSON encoding).");
|
||||
theModel.put("errorMsg",
|
||||
toDisplayError("Message body does not appear to be a valid FHIR resource instance document. Body should start with '<' (for XML encoding) or '{' (for JSON encoding).", null));
|
||||
return;
|
||||
}
|
||||
} catch (DataFormatException e) {
|
||||
ourLog.warn("Failed to parse resource", e);
|
||||
theModel.put("errorMsg", "Failed to parse message body. Error was: " + e.getMessage());
|
||||
theModel.put("errorMsg", toDisplayError("Failed to parse message body. Error was: " + e.getMessage(), e));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -671,11 +673,7 @@ public class Controller extends BaseController {
|
||||
}
|
||||
|
||||
IHistoryTyped<?> hist2;
|
||||
if (client.getFhirContext().getVersion().getVersion() == FhirVersionEnum.DSTU1) {
|
||||
hist2 = hist1.andReturnDstu1Bundle();
|
||||
} else {
|
||||
hist2 = hist1.andReturnBundle(client.getFhirContext().getResourceDefinition("Bundle").getImplementingClass(IBaseBundle.class));
|
||||
}
|
||||
hist2 = hist1.andReturnBundle(client.getFhirContext().getResourceDefinition("Bundle").getImplementingClass(IBaseBundle.class));
|
||||
|
||||
if (since != null) {
|
||||
hist2.since(since);
|
||||
@ -694,8 +692,8 @@ public class Controller extends BaseController {
|
||||
|
||||
}
|
||||
|
||||
|
||||
private boolean extractSearchParamsDstu2(IBaseResource theConformance, String resourceName, TreeSet<String> includes, TreeSet<String> theRevIncludes, TreeSet<String> sortParams, boolean haveSearchParams, List<List<String>> queryIncludes) {
|
||||
private boolean extractSearchParamsDstu2(IBaseResource theConformance, String resourceName, TreeSet<String> includes, TreeSet<String> theRevIncludes, TreeSet<String> sortParams,
|
||||
boolean haveSearchParams, List<List<String>> queryIncludes) {
|
||||
ca.uhn.fhir.model.dstu2.resource.Conformance conformance = (ca.uhn.fhir.model.dstu2.resource.Conformance) theConformance;
|
||||
for (ca.uhn.fhir.model.dstu2.resource.Conformance.Rest nextRest : conformance.getRest()) {
|
||||
for (ca.uhn.fhir.model.dstu2.resource.Conformance.RestResource nextRes : nextRest.getResource()) {
|
||||
@ -731,7 +729,8 @@ public class Controller extends BaseController {
|
||||
return haveSearchParams;
|
||||
}
|
||||
|
||||
private boolean extractSearchParamsDstu3CapabilityStatement(IBaseResource theConformance, String resourceName, TreeSet<String> includes, TreeSet<String> theRevIncludes, TreeSet<String> sortParams, boolean haveSearchParams, List<List<String>> queryIncludes) {
|
||||
private boolean extractSearchParamsDstu3CapabilityStatement(IBaseResource theConformance, String resourceName, TreeSet<String> includes, TreeSet<String> theRevIncludes, TreeSet<String> sortParams,
|
||||
boolean haveSearchParams, List<List<String>> queryIncludes) {
|
||||
CapabilityStatement conformance = (org.hl7.fhir.dstu3.model.CapabilityStatement) theConformance;
|
||||
for (CapabilityStatementRestComponent nextRest : conformance.getRest()) {
|
||||
for (CapabilityStatementRestResourceComponent nextRes : nextRest.getResource()) {
|
||||
@ -754,11 +753,38 @@ public class Controller extends BaseController {
|
||||
// scan for revinclude candidates
|
||||
for (CapabilityStatementRestResourceSearchParamComponent next : nextRes.getSearchParam()) {
|
||||
if (next.getTypeElement().getValue() == org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.REFERENCE) {
|
||||
// for (CodeType nextTargetType : next.getTarget()) {
|
||||
// if (nextTargetType.getValue().equals(resourceName)) {
|
||||
// theRevIncludes.add(nextRes.getTypeElement().getValue() + ":" + next.getName());
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return haveSearchParams;
|
||||
}
|
||||
|
||||
private boolean extractSearchParamsR4CapabilityStatement(IBaseResource theConformance, String resourceName, TreeSet<String> includes, TreeSet<String> theRevIncludes, TreeSet<String> sortParams,
|
||||
boolean haveSearchParams, List<List<String>> queryIncludes) {
|
||||
org.hl7.fhir.r4.model.CapabilityStatement conformance = (org.hl7.fhir.r4.model.CapabilityStatement) theConformance;
|
||||
for (org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestComponent nextRest : conformance.getRest()) {
|
||||
for (org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestResourceComponent nextRes : nextRest.getResource()) {
|
||||
if (nextRes.getTypeElement().getValue().equals(resourceName)) {
|
||||
for (org.hl7.fhir.r4.model.StringType next : nextRes.getSearchInclude()) {
|
||||
if (next.isEmpty() == false) {
|
||||
includes.add(next.getValue());
|
||||
}
|
||||
}
|
||||
for (org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent next : nextRes.getSearchParam()) {
|
||||
if (next.getTypeElement().getValue() != org.hl7.fhir.r4.model.Enumerations.SearchParamType.COMPOSITE) {
|
||||
sortParams.add(next.getNameElement().getValue());
|
||||
}
|
||||
}
|
||||
if (nextRes.getSearchParam().size() > 0) {
|
||||
haveSearchParams = true;
|
||||
}
|
||||
} else {
|
||||
// It's a different resource from the one we're searching, so
|
||||
// scan for revinclude candidates
|
||||
for (org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent next : nextRes.getSearchParam()) {
|
||||
if (next.getTypeElement().getValue() == org.hl7.fhir.r4.model.Enumerations.SearchParamType.REFERENCE) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user