Merge branch 'master' of github.com:jamesagnew/hapi-fhir

This commit is contained in:
James Agnew 2016-06-27 08:24:33 -04:00
commit 8c8b7b8234
87 changed files with 1761 additions and 872 deletions

View File

@ -1,16 +1,24 @@
package example;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.util.List;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Update;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor;
import ca.uhn.fhir.rest.server.interceptor.auth.IAuthRule;
import ca.uhn.fhir.rest.server.interceptor.auth.RuleBuilder;
@ -87,4 +95,43 @@ public class AuthorizationInterceptors {
}
//END SNIPPET: patientAndAdmin
//START SNIPPET: conditionalUpdate
@Update()
public MethodOutcome update(
@IdParam IdDt theId,
@ResourceParam Patient theResource,
@ConditionalUrlParam String theConditionalUrl,
RequestDetails theRequestDetails) {
// If we're processing a conditional URL...
if (isNotBlank(theConditionalUrl)) {
// Pretend we've done the conditional processing. Now let's
// notify the interceptors that an update has been performed
// and supply the actual ID that's being updated
IdDt actual = new IdDt("Patient", "1123");
// There are a number of possible constructors for ActionRequestDetails.
// You should supply as much detail about the sub-operation as possible
IServerInterceptor.ActionRequestDetails subRequest =
new IServerInterceptor.ActionRequestDetails(theRequestDetails, actual);
// Notify the interceptors
subRequest.notifyIncomingRequestPreHandled(RestOperationTypeEnum.UPDATE);
}
// In a real server, perhaps we would process the conditional
// request differently and follow a separate path. Either way,
// let's pretend there is some storage code here.
theResource.setId(theId.withVersion("2"));
MethodOutcome retVal = new MethodOutcome();
retVal.setCreated(true);
retVal.setResource(theResource);
return retVal;
}
//END SNIPPET: conditionalUpdate
}

View File

@ -30,6 +30,7 @@ import org.hl7.fhir.instance.model.api.IBase;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.util.ValidateUtil;
public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChildDefinition {
private final IAccessor myAccessor;
@ -46,7 +47,7 @@ public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChil
BaseRuntimeDeclaredChildDefinition(Field theField, Child theChildAnnotation, Description theDescriptionAnnotation, String theElementName) throws ConfigurationException {
super();
Validate.notNull(theField, "No field speficied");
Validate.inclusiveBetween(0, Integer.MAX_VALUE, theChildAnnotation.min(), "Min must be >= 0");
ValidateUtil.isGreaterThanOrEqualTo(theChildAnnotation.min(), 0, "Min must be >= 0");
Validate.isTrue(theChildAnnotation.max() == -1 || theChildAnnotation.max() >= theChildAnnotation.min(), "Max must be >= Min (unless it is -1 / unlimited)");
Validate.notBlank(theElementName, "Element name must not be blank");

View File

@ -24,7 +24,6 @@ import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.util.CoverageIgnore;
public class MethodOutcome {
@ -33,7 +32,6 @@ public class MethodOutcome {
private IIdType myId;
private IBaseOperationOutcome myOperationOutcome;
private IBaseResource myResource;
private IdDt myVersionId;
/**
* Constructor
@ -91,27 +89,6 @@ public class MethodOutcome {
myCreated = theCreated;
}
/**
* @deprecated Use the constructor which accepts a single IIdType parameter, and include the logical ID and version ID in that IIdType instance
*/
@Deprecated
@CoverageIgnore
public MethodOutcome(IIdType theId, IdDt theVersionId) {
myId = theId;
myVersionId = theVersionId;
}
/**
* @deprecated Use the constructor which accepts a single IdDt parameter, and include the logical ID and version ID in that IdDt instance
*/
@Deprecated
@CoverageIgnore
public MethodOutcome(IIdType theId, IdDt theVersionId, IBaseOperationOutcome theBaseOperationOutcome) {
myId = theId;
myVersionId = theVersionId;
myOperationOutcome = theBaseOperationOutcome;
}
/**
* Constructor
*
@ -122,6 +99,16 @@ public class MethodOutcome {
myId = theId;
}
/**
* Constructor
*
* @param theOperationOutcome
* The operation outcome resource to return
*/
public MethodOutcome(IBaseOperationOutcome theOperationOutcome) {
myOperationOutcome = theOperationOutcome;
}
/**
* This will be set to {@link Boolean#TRUE} for instance of MethodOutcome which are
* returned to client instances, if the server has responded with an HTTP 201 Created.
@ -152,15 +139,6 @@ public class MethodOutcome {
return myResource;
}
/**
* @deprecated {@link MethodOutcome#getId()} should return the complete ID including version if it is available
*/
@Deprecated
@CoverageIgnore
public IdDt getVersionId() {
return myVersionId;
}
/**
* If not null, indicates whether the resource was created (as opposed to being updated). This is generally not needed, since the server can assume based on the method being called whether the
* result was a creation or an update. However, it can be useful if you are implementing an update method that does a create if the ID doesn't already exist.
@ -205,13 +183,4 @@ public class MethodOutcome {
myResource = theResource;
}
/**
* @deprecated Put the ID and version ID into the same IdDt instance and pass it to {@link #setId(IIdType)}
*/
@Deprecated
@CoverageIgnore
public void setVersionId(IdDt theVersionId) {
myVersionId = theVersionId;
}
}

View File

@ -1663,7 +1663,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
@Override
public MethodOutcome invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws BaseServerResponseException {
MethodOutcome response = MethodUtil.process2xxResponse(myContext, myResourceName, theResponseStatusCode, theResponseMimeType, theResponseReader, theHeaders);
MethodOutcome response = MethodUtil.process2xxResponse(myContext, theResponseStatusCode, theResponseMimeType, theResponseReader, theHeaders);
if (theResponseStatusCode == Constants.STATUS_HTTP_201_CREATED) {
response.setCreated(true);
}

View File

@ -40,7 +40,6 @@ import org.hl7.fhir.instance.model.api.IIdType;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.PreferReturnEnum;
@ -167,7 +166,7 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
if (myReturnVoid) {
return null;
}
MethodOutcome retVal = MethodUtil.process2xxResponse(getContext(), getResourceName(), theResponseStatusCode, theResponseMimeType, theResponseReader, theHeaders);
MethodOutcome retVal = MethodUtil.process2xxResponse(getContext(), theResponseStatusCode, theResponseMimeType, theResponseReader, theHeaders);
return retVal;
} else {
throw processNon2xxResponseAndReturnExceptionToThrow(theResponseStatusCode, theResponseMimeType, theResponseReader);
@ -283,7 +282,7 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
}
}
protected static void parseContentLocation(FhirContext theContext, MethodOutcome theOutcomeToPopulate, String theResourceName, String theLocationHeader) {
protected static void parseContentLocation(FhirContext theContext, MethodOutcome theOutcomeToPopulate, String theLocationHeader) {
if (StringUtils.isBlank(theLocationHeader)) {
return;
}
@ -291,22 +290,6 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
IIdType id = theContext.getVersion().newIdType();
id.setValue(theLocationHeader);
theOutcomeToPopulate.setId(id);
String resourceNamePart = "/" + theResourceName + "/";
int resourceIndex = theLocationHeader.lastIndexOf(resourceNamePart);
if (resourceIndex > -1) {
int idIndexStart = resourceIndex + resourceNamePart.length();
int idIndexEnd = theLocationHeader.indexOf('/', idIndexStart);
if (idIndexEnd == -1) {
// nothing
} else {
String versionIdPart = "/_history/";
int historyIdStart = theLocationHeader.indexOf(versionIdPart, idIndexEnd);
if (historyIdStart != -1) {
theOutcomeToPopulate.setVersionId(new IdDt(theLocationHeader.substring(historyIdStart + versionIdPart.length())));
}
}
}
}
}

View File

@ -747,7 +747,7 @@ public class MethodUtil {
}
public static MethodOutcome process2xxResponse(FhirContext theContext, String theResourceName, int theResponseStatusCode, String theResponseMimeType, Reader theResponseReader, Map<String, List<String>> theHeaders) {
public static MethodOutcome process2xxResponse(FhirContext theContext, int theResponseStatusCode, String theResponseMimeType, Reader theResponseReader, Map<String, List<String>> theHeaders) {
List<String> locationHeaders = new ArrayList<String>();
List<String> lh = theHeaders.get(Constants.HEADER_LOCATION_LC);
if (lh != null) {
@ -761,7 +761,7 @@ public class MethodUtil {
MethodOutcome retVal = new MethodOutcome();
if (locationHeaders != null && locationHeaders.size() > 0) {
String locationHeader = locationHeaders.get(0);
BaseOutcomeReturningMethodBinding.parseContentLocation(theContext, retVal, theResourceName, locationHeader);
BaseOutcomeReturningMethodBinding.parseContentLocation(theContext, retVal, locationHeader);
}
if (theResponseStatusCode != Constants.STATUS_HTTP_204_NO_CONTENT) {
EncodingEnum ct = EncodingEnum.forContentType(theResponseMimeType);

View File

@ -112,7 +112,7 @@ public class OperationMethodBinding extends BaseResourceReturningMethodBinding {
myName = theOperationName;
if (theContext.getVersion().getVersion().isEquivalentTo(FhirVersionEnum.DSTU1)) {
throw new ConfigurationException("@" + Operation.class.getSimpleName() + " methods are not supported on servers for FHIR version " + theContext.getVersion().getVersion().name());
throw new ConfigurationException("@" + Operation.class.getSimpleName() + " methods are not supported on servers for FHIR version " + theContext.getVersion().getVersion().name() + " - Found one on class " + theMethod.getDeclaringClass().getName());
}
if (theReturnTypeFromRp != null) {

View File

@ -83,7 +83,7 @@ public class UpdateMethodBinding extends BaseOutcomeReturningMethodBindingWithRe
if (isNotBlank(locationHeader)) {
MethodOutcome mo = new MethodOutcome();
parseContentLocation(getContext(), mo, getResourceName(), locationHeader);
parseContentLocation(getContext(), mo, locationHeader);
if (mo.getId() == null || mo.getId().isEmpty()) {
throw new InvalidRequestException("Invalid Content-Location header for resource " + getResourceName() + ": " + locationHeader);
}

View File

@ -26,7 +26,6 @@ import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
@ -41,6 +40,7 @@ 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.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.ValidateUtil;
@SuppressWarnings("deprecation")
public class DateParam extends BaseParamWithPrefix<DateParam> implements IQueryParameterType , IQueryParameterOr<DateParam> {
@ -81,7 +81,7 @@ public class DateParam extends BaseParamWithPrefix<DateParam> implements IQueryP
* Constructor
*/
public DateParam(ParamPrefixEnum thePrefix, long theDate) {
Validate.inclusiveBetween(1, Long.MAX_VALUE, theDate, "theDate must not be 0 or negative");
ValidateUtil.isGreaterThan(theDate, 0, "theDate must not be 0 or negative");
setPrefix(thePrefix);
setValue(new Date(theDate));
}
@ -138,7 +138,7 @@ public class DateParam extends BaseParamWithPrefix<DateParam> implements IQueryP
*/
@Deprecated
public DateParam(QuantityCompararatorEnum theComparator, long theDate) {
Validate.inclusiveBetween(1, Long.MAX_VALUE, theDate, "theDate must not be 0 or negative");
ValidateUtil.isGreaterThan(theDate, 0, "theDate must not be 0 or negative");
setPrefix(toPrefix(theComparator));
setValue(new Date(theDate));
}

View File

@ -176,9 +176,6 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
if (response.getId().hasVersionIdPart()) {
b.append("/" + Constants.PARAM_HISTORY + "/");
b.append(response.getId().getVersionIdPart());
} else if (response.getVersionId() != null && response.getVersionId().isEmpty() == false) {
b.append("/" + Constants.PARAM_HISTORY + "/");
b.append(response.getVersionId().getValue());
}
theResponse.addHeader(headerLocation, b.toString());

View File

@ -371,23 +371,47 @@ public interface IServerInterceptor {
private IBaseResource myResource;
private final String myResourceType;
public ActionRequestDetails(IIdType theId, String theResourceType, FhirContext theContext, RequestDetails theRequestDetails) {
public ActionRequestDetails(RequestDetails theRequestDetails) {
myId = theRequestDetails.getId();
myResourceType = theRequestDetails.getResourceName();
myContext = theRequestDetails.getServer().getFhirContext();
myRequestDetails = theRequestDetails;
}
public ActionRequestDetails(RequestDetails theRequestDetails, FhirContext theContext, IBaseResource theResource) {
this(theRequestDetails, theContext, theContext.getResourceDefinition(theResource).getName(), theResource.getIdElement());
myResource = theResource;
}
public ActionRequestDetails(RequestDetails theRequestDetails, FhirContext theContext, String theResourceType, IIdType theId) {
myId = theId;
myResourceType = theResourceType;
myContext = theContext;
myRequestDetails = theRequestDetails;
}
public ActionRequestDetails(IIdType theId, String theResourceType, IBaseResource theResource, FhirContext theContext, RequestDetails theRequestDetails) {
this(theId, theResourceType, theContext, theRequestDetails);
public ActionRequestDetails(RequestDetails theRequestDetails, IBaseResource theResource) {
this(theRequestDetails, theRequestDetails.getServer().getFhirContext().getResourceDefinition(theResource).getName(), theResource.getIdElement());
myResource = theResource;
}
public ActionRequestDetails(RequestDetails theRequestDetails) {
myId = theRequestDetails.getId();
myResourceType = theRequestDetails.getResourceName();
myContext = theRequestDetails.getServer().getFhirContext();
myRequestDetails = theRequestDetails;
public ActionRequestDetails(RequestDetails theRequestDetails, IBaseResource theResource, String theResourceType, IIdType theId) {
this(theRequestDetails, theResourceType, theId);
myResource = theResource;
}
public ActionRequestDetails(RequestDetails theRequestDetails, String theResourceType, IIdType theId) {
this(theRequestDetails, theRequestDetails.getServer().getFhirContext(), theResourceType, theId);
}
/**
* Constructor
*
* @param theRequestDetails The request details to wrap
* @param theId The ID of the resource being created (note that the ID should have the resource type populated)
*/
public ActionRequestDetails(RequestDetails theRequestDetails, IIdType theId) {
this(theRequestDetails, theId.getResourceType(), theId);
}
public FhirContext getContext() {
@ -436,13 +460,6 @@ public interface IServerInterceptor {
return myRequestDetails.getUserData();
}
/**
* This method should not be called by client code
*/
public void setResource(IBaseResource theObject) {
myResource = theObject;
}
/**
* This method may be invoked by user code to notify interceptors that a nested
* operation is being invoked which is denoted by this request details.
@ -462,6 +479,13 @@ public interface IServerInterceptor {
}
}
/**
* This method should not be called by client code
*/
public void setResource(IBaseResource theObject) {
myResource = theObject;
}
}
}

View File

@ -38,4 +38,22 @@ public class ValidateUtil {
}
}
/**
* Throws {@link IllegalArgumentException} if theValue is <= theMinimum
*/
public static void isGreaterThan(long theValue, long theMinimum, String theMessage) {
if (theValue <= theMinimum) {
throw new IllegalArgumentException(theMessage);
}
}
/**
* Throws {@link IllegalArgumentException} if theValue is <= theMinimum
*/
public static void isGreaterThanOrEqualTo(long theValue, long theMinimum, String theMessage) {
if (theValue < theMinimum) {
throw new IllegalArgumentException(theMessage);
}
}
}

View File

@ -21,6 +21,28 @@ public class ValidateUtilTest {
}
}
@Test
public void testIsGreaterThan() {
ValidateUtil.isGreaterThan(2L, 1L, "");
try {
ValidateUtil.isGreaterThan(1L, 1L, "The message");
fail();
} catch (IllegalArgumentException e) {
assertEquals("The message", e.getMessage());
}
}
@Test
public void testIsGreaterThanOrEqualTo() {
ValidateUtil.isGreaterThanOrEqualTo(1L, 1L, "");
try {
ValidateUtil.isGreaterThanOrEqualTo(0L, 1L, "The message");
fail();
} catch (IllegalArgumentException e) {
assertEquals("The message", e.getMessage());
}
}
@Test
public void testIsNotBlank() {
ValidateUtil.isNotBlankOrThrowInvalidRequest("aa", "");

View File

@ -27,6 +27,8 @@ import ca.uhn.fhir.jpa.demo.FhirServerConfigDstu3;
public class RunServerCommand extends BaseCommand {
private static final String OPTION_LOWMEM = "lowmem";
private static final String OPTION_ALLOW_EXTERNAL_REFS = "allow-external-refs";
private static final int DEFAULT_PORT = 8080;
private static final String OPTION_P = "p";
@ -45,7 +47,8 @@ public class RunServerCommand extends BaseCommand {
Options options = new Options();
addFhirVersionOption(options);
options.addOption(OPTION_P, "port", true, "The port to listen on (default is " + DEFAULT_PORT + ")");
options.addOption(null, "lowmem", false, "If this flag is set, the server will operate in low memory mode (some features disabled)");
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");
return options;
}
@ -61,9 +64,14 @@ public class RunServerCommand extends BaseCommand {
public void run(CommandLine theCommandLine) throws ParseException {
myPort = parseOptionInteger(theCommandLine, OPTION_P, DEFAULT_PORT);
if (theCommandLine.hasOption("lowmem")) {
if (theCommandLine.hasOption(OPTION_LOWMEM)) {
ourLog.info("Running in low memory mode, some features disabled");
System.setProperty("lowmem", "lowmem");
System.setProperty(OPTION_LOWMEM, OPTION_LOWMEM);
}
if (theCommandLine.hasOption(OPTION_ALLOW_EXTERNAL_REFS)) {
ourLog.info("Server is configured to allow external references");
ContextHolder.setAllowExternalRefs(true);
}
ContextHolder.setCtx(getSpecVersionContext(theCommandLine));

View File

@ -7,6 +7,7 @@ import ca.uhn.fhir.context.FhirContext;
public class ContextHolder {
private static boolean ourAllowExternalRefs;
private static FhirContext ourCtx;
private static String ourPath;
@ -15,6 +16,19 @@ public class ContextHolder {
return ourCtx;
}
public static String getPath() {
Validate.notNull(ourPath, "Context not set");
return ourPath;
}
public static boolean isAllowExternalRefs() {
return ourAllowExternalRefs;
}
public static void setAllowExternalRefs(boolean theAllowExternalRefs) {
ourAllowExternalRefs = theAllowExternalRefs;
}
public static void setCtx(FhirContext theCtx) throws ParseException {
switch (theCtx.getVersion().getVersion()) {
case DSTU2:
@ -30,9 +44,4 @@ public class ContextHolder {
ourCtx = theCtx;
}
public static String getPath() {
Validate.notNull(ourPath, "Context not set");
return ourPath;
}
}

View File

@ -147,6 +147,9 @@ public class JpaServerDemo extends RestfulServer {
this.registerInterceptor(interceptor);
}
DaoConfig daoConfig = myAppCtx.getBean(DaoConfig.class);
daoConfig.setAllowExternalReferences(ContextHolder.isAllowExternalRefs());
}
}

View File

@ -133,10 +133,6 @@ public class JaxRsResponseDstu3Test {
@Test
public void testNoOutcomeXml() throws IOException {
int operationStatus = Constants.STATUS_HTTP_204_NO_CONTENT;
boolean allowPrefer = true;
String resourceName = "Patient";
MethodOutcome methodOutcome = new MethodOutcome(null);
response.getRequestDetails().getParameters().put(Constants.PARAM_FORMAT, new String[]{Constants.CT_XML});
boolean addContentLocationHeader = true;
boolean respondGzip = true;

View File

@ -101,6 +101,7 @@ public class BaseDstu3Config extends BaseConfig {
@Bean(name = "mySystemProviderDstu3")
public ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3 systemProviderDstu3() {
ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3 retVal = new ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3();
retVal.setContext(defaultFhirContext());
retVal.setDao(systemDaoDstu3());
return retVal;
}

View File

@ -129,7 +129,6 @@ import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.method.MethodUtil;
import ca.uhn.fhir.rest.method.QualifiedParamList;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.StringAndListParam;
@ -1076,8 +1075,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
}
@SuppressWarnings("unchecked")
protected ResourceTable updateEntity(final IBaseResource theResource, ResourceTable theEntity, boolean theUpdateHistory, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
boolean theUpdateVersion, Date theUpdateTime, RequestDetails theRequestDetails) {
protected ResourceTable updateEntity(final IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
boolean theUpdateVersion, Date theUpdateTime) {
ourLog.info("Starting entity update");
/*
@ -1085,7 +1084,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
*/
if (theResource != null) {
if (thePerformIndexing) {
validateResourceForStorage((T) theResource, theEntity, theRequestDetails);
validateResourceForStorage((T) theResource, theEntity);
}
String resourceType = myContext.getResourceDefinition(theResource).getName();
if (isNotBlank(theEntity.getResourceType()) && !theEntity.getResourceType().equals(resourceType)) {
@ -1175,7 +1174,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
coordsParams = extractSearchParamCoords(theEntity, theResource);
// ourLog.info("Indexing resource: {}", entity.getId());
ourLog.info("Storing date indexes: {}", dateParams);
ourLog.trace("Storing date indexes: {}", dateParams);
tokenParams = new HashSet<ResourceIndexedSearchParamToken>();
for (BaseResourceIndexedSearchParam next : extractSearchParamTokens(theEntity, theResource)) {
@ -1394,9 +1393,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
return theEntity;
}
protected ResourceTable updateEntity(IBaseResource theResource, ResourceTable entity, boolean theUpdateHistory, Date theDeletedTimestampOrNull, Date theUpdateTime,
RequestDetails theRequestDetails) {
return updateEntity(theResource, entity, theUpdateHistory, theDeletedTimestampOrNull, true, true, theUpdateTime, theRequestDetails);
protected ResourceTable updateEntity(IBaseResource theResource, ResourceTable entity, Date theDeletedTimestampOrNull, Date theUpdateTime) {
return updateEntity(theResource, entity, theDeletedTimestampOrNull, true, true, theUpdateTime);
}
protected void validateDeleteConflictsEmptyOrThrowException(List<DeleteConflict> theDeleteConflicts) {
@ -1423,10 +1421,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
* The resource that is about to be persisted
* @param theEntityToSave
* TODO
* @param theRequestDetails
* TODO
*/
protected void validateResourceForStorage(T theResource, ResourceTable theEntityToSave, RequestDetails theRequestDetails) {
protected void validateResourceForStorage(T theResource, ResourceTable theEntityToSave) {
Object tag = null;
if (theResource instanceof IResource) {
IResource res = (IResource) theResource;

View File

@ -197,20 +197,26 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
validateOkToDelete(deleteConflicts, entity);
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(theId, theId.getResourceType(), getContext(), theRequestDetails);
notifyInterceptors(RestOperationTypeEnum.DELETE, requestDetails);
if (theRequestDetails != null) {
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getContext(), theId.getResourceType(), theId);
notifyInterceptors(RestOperationTypeEnum.DELETE, requestDetails);
}
Date updateTime = new Date();
ResourceTable savedEntity = updateEntity(null, entity, true, updateTime, updateTime, theRequestDetails);
ResourceTable savedEntity = updateEntity(null, entity, updateTime, updateTime);
// Notify JPA interceptors
T resourceToDelete = toResource(myResourceType, entity, false);
theRequestDetails.getRequestOperationCallback().resourceDeleted(resourceToDelete);
for (IServerInterceptor next : getConfig().getInterceptors()) {
if (next instanceof IJpaServerInterceptor) {
((IJpaServerInterceptor) next).resourceDeleted(requestDetails, entity);
if (theRequestDetails != null) {
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getContext(), theId.getResourceType(), theId);
T resourceToDelete = toResource(myResourceType, entity, false);
theRequestDetails.getRequestOperationCallback().resourceDeleted(resourceToDelete);
for (IServerInterceptor next : getConfig().getInterceptors()) {
if (next instanceof IJpaServerInterceptor) {
((IJpaServerInterceptor) next).resourceDeleted(requestDetails, entity);
}
}
}
return savedEntity;
}
@ -245,12 +251,12 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
// Notify interceptors
IdDt idToDelete = entity.getIdDt();
ActionRequestDetails requestDetails = new ActionRequestDetails(idToDelete, idToDelete.getResourceType(), getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, idToDelete.getResourceType(), idToDelete);
notifyInterceptors(RestOperationTypeEnum.DELETE, requestDetails);
// Perform delete
Date updateTime = new Date();
updateEntity(null, entity, true, updateTime, updateTime, theRequestDetails);
updateEntity(null, entity, updateTime, updateTime);
// Notify JPA interceptors
T resourceToDelete = toResource(myResourceType, entity, false);
@ -322,18 +328,23 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
}
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(theResource.getIdElement(), toResourceName(theResource), theResource, getContext(), theRequestDetails);
notifyInterceptors(RestOperationTypeEnum.CREATE, requestDetails);
if (theRequestDetails != null) {
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getContext(), theResource);
notifyInterceptors(RestOperationTypeEnum.CREATE, requestDetails);
}
// Perform actual DB update
updateEntity(theResource, entity, false, null, thePerformIndexing, true, theUpdateTime, theRequestDetails);
updateEntity(theResource, entity, null, thePerformIndexing, true, theUpdateTime);
theResource.setId(entity.getIdDt());
// Notify JPA interceptors
theRequestDetails.getRequestOperationCallback().resourceCreated(theResource);
for (IServerInterceptor next : getConfig().getInterceptors()) {
if (next instanceof IJpaServerInterceptor) {
((IJpaServerInterceptor) next).resourceCreated(requestDetails, entity);
if (theRequestDetails != null) {
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getContext(), theResource);
theRequestDetails.getRequestOperationCallback().resourceCreated(theResource);
for (IServerInterceptor next : getConfig().getInterceptors()) {
if (next instanceof IJpaServerInterceptor) {
((IJpaServerInterceptor) next).resourceCreated(requestDetails, entity);
}
}
}
@ -401,7 +412,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
@Override
public TagList getAllResourceTags(RequestDetails theRequestDetails) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(null, null, getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails);
notifyInterceptors(RestOperationTypeEnum.GET_TAGS, requestDetails);
StopWatch w = new StopWatch();
@ -424,7 +435,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
@Override
public TagList getTags(IIdType theResourceId, RequestDetails theRequestDetails) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(theResourceId, null, getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, null, theResourceId);
notifyInterceptors(RestOperationTypeEnum.GET_TAGS, requestDetails);
StopWatch w = new StopWatch();
@ -436,7 +447,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
@Override
public IBundleProvider history(Date theSince, Date theUntil, RequestDetails theRequestDetails) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(null, null, getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails);
notifyInterceptors(RestOperationTypeEnum.HISTORY_TYPE, requestDetails);
StopWatch w = new StopWatch();
@ -448,7 +459,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
@Override
public IBundleProvider history(final IIdType theId, final Date theSince, Date theUntil, RequestDetails theRequestDetails) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(theId, getResourceName(), getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getResourceName(), theId);
notifyInterceptors(RestOperationTypeEnum.HISTORY_INSTANCE, requestDetails);
StopWatch w = new StopWatch();
@ -547,7 +558,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
@Override
public <MT extends IBaseMetaType> MT metaAddOperation(IIdType theResourceId, MT theMetaAdd, RequestDetails theRequestDetails) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(theResourceId, getResourceName(), getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getResourceName(), theResourceId);
notifyInterceptors(RestOperationTypeEnum.META_ADD, requestDetails);
StopWatch w = new StopWatch();
@ -577,7 +588,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
@Override
public <MT extends IBaseMetaType> MT metaDeleteOperation(IIdType theResourceId, MT theMetaDel, RequestDetails theRequestDetails) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(theResourceId, getResourceName(), getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getResourceName(), theResourceId);
notifyInterceptors(RestOperationTypeEnum.META_DELETE, requestDetails);
StopWatch w = new StopWatch();
@ -609,7 +620,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
@Override
public <MT extends IBaseMetaType> MT metaGetOperation(Class<MT> theType, IIdType theId, RequestDetails theRequestDetails) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(theId, getResourceName(), getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getResourceName(), theId);
notifyInterceptors(RestOperationTypeEnum.META, requestDetails);
Set<TagDefinition> tagDefs = new HashSet<TagDefinition>();
@ -628,7 +639,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
@Override
public <MT extends IBaseMetaType> MT metaGetOperation(Class<MT> theType, RequestDetails theRequestDetails) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName(), getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getResourceName(), null);
notifyInterceptors(RestOperationTypeEnum.META, requestDetails);
String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t WHERE t.myResourceType = :res_type)";
@ -704,9 +715,11 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
validateResourceTypeAndThrowIllegalArgumentException(theId);
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(theId, getResourceName(), getContext(), theRequestDetails);
RestOperationTypeEnum operationType = theId.hasVersionIdPart() ? RestOperationTypeEnum.VREAD : RestOperationTypeEnum.READ;
notifyInterceptors(operationType, requestDetails);
if (theRequestDetails != null) {
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getResourceName(), theId);
RestOperationTypeEnum operationType = theId.hasVersionIdPart() ? RestOperationTypeEnum.VREAD : RestOperationTypeEnum.READ;
notifyInterceptors(operationType, requestDetails);
}
StopWatch w = new StopWatch();
BaseHasResource entity = readEntity(theId);
@ -790,14 +803,14 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
}
@Override
public void reindex(T theResource, ResourceTable theEntity, RequestDetails theRequestDetails) {
updateEntity(theResource, theEntity, false, null, true, false, theEntity.getUpdatedDate(), theRequestDetails);
public void reindex(T theResource, ResourceTable theEntity) {
updateEntity(theResource, theEntity, null, true, false, theEntity.getUpdatedDate());
}
@Override
public void removeTag(IIdType theId, TagTypeEnum theTagType, String theScheme, String theTerm, RequestDetails theRequestDetails) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(theId, getResourceName(), getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getResourceName(), theId);
notifyInterceptors(RestOperationTypeEnum.DELETE_TAGS, requestDetails);
StopWatch w = new StopWatch();
@ -838,7 +851,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
@Override
public IBundleProvider search(final SearchParameterMap theParams) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName(), getContext(), theParams.getRequestDetails());
ActionRequestDetails requestDetails = new ActionRequestDetails(theParams.getRequestDetails(), getContext(), getResourceName(), null);
notifyInterceptors(RestOperationTypeEnum.SEARCH_TYPE, requestDetails);
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this, myResourceIndexedSearchParamUriDao, myForcedIdDao,
@ -1010,11 +1023,11 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
}
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(resourceId, getResourceName(), theResource, getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, theResource, getResourceName(), resourceId);
notifyInterceptors(RestOperationTypeEnum.UPDATE, requestDetails);
// Perform update
ResourceTable savedEntity = updateEntity(theResource, entity, true, null, thePerformIndexing, true, new Date(), theRequestDetails);
ResourceTable savedEntity = updateEntity(theResource, entity, null, thePerformIndexing, true, new Date());
// Notify interceptors
theRequestDetails.getRequestOperationCallback().resourceUpdated(theResource);

View File

@ -37,8 +37,6 @@ import javax.persistence.criteria.Root;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
@ -50,7 +48,6 @@ import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
import ca.uhn.fhir.jpa.dao.data.ITermConceptDao;
import ca.uhn.fhir.jpa.entity.ForcedId;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.util.ReindexFailureException;
import ca.uhn.fhir.jpa.util.StopWatch;
import ca.uhn.fhir.model.api.TagList;
@ -79,21 +76,20 @@ public abstract class BaseHapiFhirSystemDao<T, MT> extends BaseHapiFhirDao<IBase
@Override
public void deleteAllTagsOnServer(RequestDetails theRequestDetails) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(null, null, getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails);
notifyInterceptors(RestOperationTypeEnum.DELETE_TAGS, requestDetails);
myEntityManager.createQuery("DELETE from ResourceTag t").executeUpdate();
}
private int doPerformReindexingPass(final Integer theCount, final RequestDetails theRequestDetails) {
private int doPerformReindexingPass(final Integer theCount) {
TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRED);
int retVal = doPerformReindexingPassForResources(theCount, theRequestDetails, txTemplate);
retVal += doPerformReindexingPassForConcepts(txTemplate);
int retVal = doPerformReindexingPassForResources(theCount, txTemplate);
return retVal;
}
private int doPerformReindexingPassForResources(final Integer theCount, final RequestDetails theRequestDetails, TransactionTemplate txTemplate) {
private int doPerformReindexingPassForResources(final Integer theCount, TransactionTemplate txTemplate) {
return txTemplate.execute(new TransactionCallback<Integer>() {
@SuppressWarnings("unchecked")
@Override
@ -135,7 +131,7 @@ public abstract class BaseHapiFhirSystemDao<T, MT> extends BaseHapiFhirDao<IBase
@SuppressWarnings("rawtypes")
final IFhirResourceDao dao = getDao(resource.getClass());
dao.reindex(resource, resourceTable, theRequestDetails);
dao.reindex(resource, resourceTable);
} catch (Exception e) {
ourLog.error("Failed to index resource {}: {}", new Object[] { resourceTable.getIdDt(), e.toString(), e });
throw new ReindexFailureException(resourceTable.getId());
@ -152,41 +148,10 @@ public abstract class BaseHapiFhirSystemDao<T, MT> extends BaseHapiFhirDao<IBase
});
}
private int doPerformReindexingPassForConcepts(TransactionTemplate txTemplate) {
return txTemplate.execute(new TransactionCallback<Integer>() {
@Override
public Integer doInTransaction(TransactionStatus theStatus) {
int maxResult = 10000;
Page<TermConcept> resources = myTermConceptDao.findResourcesRequiringReindexing(new PageRequest(0, maxResult));
if (resources.hasContent() == false) {
return 0;
}
ourLog.info("Indexing {} / {} concepts", resources.getContent().size(), resources.getTotalElements());
int count = 0;
long start = System.currentTimeMillis();
for (TermConcept resourceTable : resources) {
resourceTable.setIndexStatus(BaseHapiFhirDao.INDEX_STATUS_INDEXED);
myTermConceptDao.save(resourceTable);
count++;
}
long delay = System.currentTimeMillis() - start;
long avg = (delay / resources.getContent().size());
ourLog.info("Indexed {} / {} concepts in {}ms - Avg {}ms / resource", new Object[] { count, resources.getContent().size(), delay, avg });
return resources.getContent().size();
}
});
}
@Override
public TagList getAllTags(RequestDetails theRequestDetails) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(null, null, getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails);
notifyInterceptors(RestOperationTypeEnum.GET_TAGS, requestDetails);
StopWatch w = new StopWatch();
@ -221,7 +186,7 @@ public abstract class BaseHapiFhirSystemDao<T, MT> extends BaseHapiFhirDao<IBase
@Override
public IBundleProvider history(Date theSince, Date theUntil, RequestDetails theRequestDetails) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(null, null, getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails);
notifyInterceptors(RestOperationTypeEnum.HISTORY_SYSTEM, requestDetails);
StopWatch w = new StopWatch();
@ -301,9 +266,9 @@ public abstract class BaseHapiFhirSystemDao<T, MT> extends BaseHapiFhirDao<IBase
@Override
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public int performReindexingPass(final Integer theCount, RequestDetails theRequestDetails) {
public int performReindexingPass(final Integer theCount) {
try {
return doPerformReindexingPass(theCount, theRequestDetails);
return doPerformReindexingPass(theCount);
} catch (ReindexFailureException e) {
ourLog.warn("Reindexing failed for resource {}", e.getResourceId());
markResourceAsIndexingFailed(e.getResourceId());

View File

@ -100,7 +100,7 @@ public class FhirResourceDaoDstu2<T extends IResource> extends BaseHapiFhirResou
@Override
public MethodOutcome validate(T theResource, IIdType theId, String theRawResource, EncodingEnum theEncoding, ValidationModeEnum theMode, String theProfile, RequestDetails theRequestDetails) {
ActionRequestDetails requestDetails = new ActionRequestDetails(theId, null, theResource, getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, theResource, null, theId);
notifyInterceptors(RestOperationTypeEnum.VALIDATE, requestDetails);
if (theMode == ValidationModeEnum.DELETE) {

View File

@ -73,7 +73,7 @@ public class FhirResourceDaoPatientDstu2 extends FhirResourceDaoDstu2<Patient>im
@Override
public IBundleProvider patientInstanceEverything(HttpServletRequest theServletRequest, IIdType theId, IPrimitiveType<Integer> theCount, DateRangeParam theLastUpdated, SortSpec theSort, StringAndListParam theContent, StringAndListParam theNarrative, RequestDetails theRequestDetails) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName(), getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getResourceName(), null);
notifyInterceptors(RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE, requestDetails);
return doEverythingOperation(theId, theCount, theLastUpdated, theSort, theContent, theNarrative);
@ -82,7 +82,7 @@ public class FhirResourceDaoPatientDstu2 extends FhirResourceDaoDstu2<Patient>im
@Override
public IBundleProvider patientTypeEverything(HttpServletRequest theServletRequest, IPrimitiveType<Integer> theCount, DateRangeParam theLastUpdated, SortSpec theSort, StringAndListParam theContent, StringAndListParam theNarrative, RequestDetails theRequestDetails) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName(), getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getResourceName(), null);
notifyInterceptors(RestOperationTypeEnum.EXTENDED_OPERATION_TYPE, requestDetails);
return doEverythingOperation(null, theCount, theLastUpdated, theSort, theContent, theNarrative);

View File

@ -35,7 +35,6 @@ import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
import ca.uhn.fhir.model.dstu2.resource.Questionnaire;
import ca.uhn.fhir.model.dstu2.resource.QuestionnaireResponse;
import ca.uhn.fhir.model.dstu2.resource.ValueSet;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.validation.FhirValidator;
@ -64,8 +63,8 @@ public class FhirResourceDaoQuestionnaireResponseDstu2 extends FhirResourceDaoDs
}
@Override
protected void validateResourceForStorage(QuestionnaireResponse theResource, ResourceTable theEntityToSave, RequestDetails theRequestDetails) {
super.validateResourceForStorage(theResource, theEntityToSave, theRequestDetails);
protected void validateResourceForStorage(QuestionnaireResponse theResource, ResourceTable theEntityToSave) {
super.validateResourceForStorage(theResource, theEntityToSave);
if (!myValidateResponses) {
return;
}
@ -80,7 +79,7 @@ public class FhirResourceDaoQuestionnaireResponseDstu2 extends FhirResourceDaoDs
val.setValidateAgainstStandardSchematron(false);
FhirQuestionnaireResponseValidator module = new FhirQuestionnaireResponseValidator();
module.setResourceLoader(new JpaResourceLoader(theRequestDetails));
module.setResourceLoader(new JpaResourceLoader());
val.registerValidatorModule(module);
ValidationResult result = val.validateWithResult(myRefImplCtx.newJsonParser().parseResource(getContext().newJsonParser().encodeResourceToString(qa)));
@ -92,10 +91,8 @@ public class FhirResourceDaoQuestionnaireResponseDstu2 extends FhirResourceDaoDs
public class JpaResourceLoader implements IResourceLoader {
private RequestDetails myRequestDetails;
public JpaResourceLoader(RequestDetails theRequestDetails) {
myRequestDetails = theRequestDetails;
public JpaResourceLoader() {
super();
}
@Override
@ -107,7 +104,7 @@ public class FhirResourceDaoQuestionnaireResponseDstu2 extends FhirResourceDaoDs
*/
if ("ValueSet".equals(theType.getSimpleName())) {
IFhirResourceDao<ValueSet> dao = getDao(ValueSet.class);
ValueSet in = dao.read(theId, myRequestDetails);
ValueSet in = dao.read(theId, null);
String encoded = getContext().newJsonParser().encodeResourceToString(in);
// TODO: this is temporary until structures-dstu2 catches up to structures-hl7org.dstu2
@ -116,7 +113,7 @@ public class FhirResourceDaoQuestionnaireResponseDstu2 extends FhirResourceDaoDs
return myRefImplCtx.newJsonParser().parseResource(theType, encoded);
} else if ("Questionnaire".equals(theType.getSimpleName())) {
IFhirResourceDao<Questionnaire> dao = getDao(Questionnaire.class);
Questionnaire vs = dao.read(theId, myRequestDetails);
Questionnaire vs = dao.read(theId, null);
return myRefImplCtx.newJsonParser().parseResource(theType, getContext().newJsonParser().encodeResourceToString(vs));
} else {
// Should not happen, validator will only ask for these two

View File

@ -27,8 +27,6 @@ import org.springframework.scheduling.annotation.Scheduled;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.SearchParameter;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
public class FhirResourceDaoSearchParameterDstu2 extends FhirResourceDaoDstu2<SearchParameter>implements IFhirResourceDaoSearchParameter<SearchParameter> {
@ -48,10 +46,9 @@ public class FhirResourceDaoSearchParameterDstu2 extends FhirResourceDaoDstu2<Se
return;
}
RequestDetails requestDetails = new ServletRequestDetails();
int count = mySystemDao.performReindexingPass(100, requestDetails);
int count = mySystemDao.performReindexingPass(100);
for (int i = 0; i < 50 && count != 0; i++) {
count = mySystemDao.performReindexingPass(100, requestDetails);
count = mySystemDao.performReindexingPass(100);
try {
Thread.sleep(DateUtils.MILLIS_PER_SECOND);
} catch (InterruptedException e) {

View File

@ -52,7 +52,6 @@ import ca.uhn.fhir.jpa.entity.SubscriptionFlaggedResource;
import ca.uhn.fhir.jpa.entity.SubscriptionTable;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.model.dstu2.resource.Subscription;
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionStatusEnum;
import ca.uhn.fhir.model.primitive.IdDt;
@ -60,9 +59,9 @@ import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.api.SortOrderEnum;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
@ -162,8 +161,8 @@ public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2<Subsc
ourLog.debug("Subscription {} search from {} to {}", new Object[] { subscription.getId().getIdPart(), new InstantDt(new Date(start)), new InstantDt(new Date(end)) });
DateRangeParam range = new DateRangeParam();
range.setLowerBound(new DateParam(QuantityCompararatorEnum.GREATERTHAN, start));
range.setUpperBound(new DateParam(QuantityCompararatorEnum.LESSTHAN, end));
range.setLowerBound(new DateParam(ParamPrefixEnum.GREATERTHAN, start));
range.setUpperBound(new DateParam(ParamPrefixEnum.LESSTHAN, end));
criteriaUrl.setLastUpdated(range);
criteriaUrl.setSort(new SortSpec(Constants.PARAM_LASTUPDATED, SortOrderEnum.ASC));
IFhirResourceDao<? extends IBaseResource> dao = getDao(resourceDef.getImplementingClass());
@ -252,7 +251,7 @@ public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2<Subsc
txTemplate.execute(new TransactionCallback<Void>() {
@Override
public Void doInTransaction(TransactionStatus theStatus) {
delete(subscriptionId, new ServletRequestDetails());
delete(subscriptionId, null);
return null;
}
});
@ -260,9 +259,9 @@ public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2<Subsc
}
@Override
protected ResourceTable updateEntity(IBaseResource theResource, ResourceTable theEntity, boolean theUpdateHistory, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
Date theUpdateTime, RequestDetails theRequestDetails) {
ResourceTable retVal = super.updateEntity(theResource, theEntity, theUpdateHistory, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theRequestDetails);
protected ResourceTable updateEntity(IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
Date theUpdateTime) {
ResourceTable retVal = super.updateEntity(theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime);
Subscription resource = (Subscription) theResource;
Long resourceId = theEntity.getId();
@ -311,8 +310,8 @@ public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2<Subsc
}
@Override
protected void validateResourceForStorage(Subscription theResource, ResourceTable theEntityToSave, RequestDetails theRequestDetails) {
super.validateResourceForStorage(theResource, theEntityToSave, theRequestDetails);
protected void validateResourceForStorage(Subscription theResource, ResourceTable theEntityToSave) {
super.validateResourceForStorage(theResource, theEntityToSave);
RuntimeResourceDefinition resDef = validateCriteriaAndReturnResourceDefinition(theResource);

View File

@ -78,7 +78,7 @@ public class FhirResourceDaoValueSetDstu2 extends FhirResourceDaoDstu2<ValueSet>
}
@Override
public ValueSet expand(IIdType theId, String theFilter) {
public ValueSet expand(IIdType theId, String theFilter, RequestDetails theRequestDetails) {
ValueSet source = loadValueSetForExpansion(theId);
return expand(source, theFilter);
@ -179,7 +179,7 @@ public class FhirResourceDaoValueSetDstu2 extends FhirResourceDaoDstu2<ValueSet>
}
@Override
public ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult validateCode(IPrimitiveType<String> theValueSetIdentifier, IIdType theId, IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, IPrimitiveType<String> theDisplay, CodingDt theCoding, CodeableConceptDt theCodeableConcept) {
public ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult validateCode(IPrimitiveType<String> theValueSetIdentifier, IIdType theId, IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, IPrimitiveType<String> theDisplay, CodingDt theCoding, CodeableConceptDt theCodeableConcept, RequestDetails theRequestDetails) {
List<IIdType> valueSetIds;
boolean haveCodeableConcept = theCodeableConcept != null && theCodeableConcept.getCoding().size() > 0;
@ -212,7 +212,7 @@ public class FhirResourceDaoValueSetDstu2 extends FhirResourceDaoDstu2<ValueSet>
}
for (IIdType nextId : valueSetIds) {
ValueSet expansion = expand(nextId, null);
ValueSet expansion = expand(nextId, null, theRequestDetails);
List<ExpansionContains> contains = expansion.getExpansion().getContains();
ValidateCodeResult result = validateCodeIsInContains(contains, toStringOrNull(theSystem), toStringOrNull(theCode), theCoding, theCodeableConcept);
if (result != null) {
@ -314,7 +314,7 @@ public class FhirResourceDaoValueSetDstu2 extends FhirResourceDaoDstu2<ValueSet>
List<IIdType> valueSetIds = findCodeSystemIdsContainingSystemAndCode(code, system);
for (IIdType nextId : valueSetIds) {
ValueSet expansion = expand(nextId, null);
ValueSet expansion = expand(nextId, null, theRequestDetails);
List<ExpansionContains> contains = expansion.getExpansion().getContains();
LookupCodeResult result = lookup(contains, system, code);
if (result != null) {

View File

@ -64,7 +64,7 @@ public class FhirSystemDaoDstu1 extends BaseHapiFhirSystemDao<List<IResource>, M
ourLog.info("Beginning transaction with {} resources", theResources.size());
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(null, null, getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails);
notifyInterceptors(RestOperationTypeEnum.TRANSACTION, requestDetails);
long start = System.currentTimeMillis();
@ -270,7 +270,7 @@ public class FhirSystemDaoDstu1 extends BaseHapiFhirSystemDao<List<IResource>, M
ResourceMetadataKeyEnum.DELETED_AT.put(resource, new InstantDt(deletedTimestampOrNull));
}
updateEntity(resource, table, table.getId() != null, deletedTimestampOrNull, updateTime, theRequestDetails);
updateEntity(resource, table, deletedTimestampOrNull, updateTime);
}
long delay = System.currentTimeMillis() - start;

View File

@ -200,7 +200,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
@Override
public MetaDt metaGetOperation(RequestDetails theRequestDetails) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(null, null, getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails);
notifyInterceptors(RestOperationTypeEnum.META, requestDetails);
String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t)";
@ -259,7 +259,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
@Transactional(propagation = Propagation.REQUIRED)
@Override
public Bundle transaction(RequestDetails theRequestDetails, Bundle theRequest) {
ActionRequestDetails requestDetails = new ActionRequestDetails(null, "Bundle", theRequest, getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, theRequest, "Bundle", null);
notifyInterceptors(RestOperationTypeEnum.TRANSACTION, requestDetails);
String actionName = "Transaction";
@ -474,7 +474,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
InstantDt deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get(nextResource);
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
updateEntity(nextResource, nextOutcome.getEntity(), false, deletedTimestampOrNull, true, false, updateTime, theRequestDetails);
updateEntity(nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, false, updateTime);
}
myEntityManager.flush();

View File

@ -143,9 +143,8 @@ public interface IFhirResourceDao<T extends IBaseResource> extends IDao {
/**
* Updates index tables associated with the given resource. Does not create a new
* version or update the resource's update time.
* @param theRequestDetails TODO
*/
void reindex(T theResource, ResourceTable theEntity, RequestDetails theRequestDetails);
void reindex(T theResource, ResourceTable theEntity);
void removeTag(IIdType theId, TagTypeEnum theTagType, String theScheme, String theTerm, RequestDetails theRequestDetails);

View File

@ -24,9 +24,11 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import ca.uhn.fhir.rest.method.RequestDetails;
public interface IFhirResourceDaoValueSet<T extends IBaseResource, CD, CC> extends IFhirResourceDao<T> {
T expand(IIdType theId, String theFilter);
T expand(IIdType theId, String theFilter, RequestDetails theRequestDetails);
T expand(T theSource, String theFilter);
@ -34,7 +36,7 @@ public interface IFhirResourceDaoValueSet<T extends IBaseResource, CD, CC> exten
void purgeCaches();
ValidateCodeResult validateCode(IPrimitiveType<String> theValueSetIdentifier, IIdType theId, IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, IPrimitiveType<String> theDisplay, CD theCoding, CC theCodeableConcept);
ValidateCodeResult validateCode(IPrimitiveType<String> theValueSetIdentifier, IIdType theId, IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, IPrimitiveType<String> theDisplay, CD theCoding, CC theCodeableConcept, RequestDetails theRequestDetails);
public class ValidateCodeResult {
private String myDisplay;

View File

@ -62,7 +62,7 @@ public interface IFhirSystemDao<T, MT> extends IDao {
*/
MT metaGetOperation(RequestDetails theRequestDetails);
int performReindexingPass(Integer theCount, RequestDetails theRequestDetails);
int performReindexingPass(Integer theCount);
T transaction(RequestDetails theRequestDetails, T theResources);

View File

@ -35,7 +35,6 @@ import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.dstu3.model.CodeableConcept;
import org.hl7.fhir.dstu3.model.Coding;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
@ -198,9 +197,9 @@ public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3<CodeSys
}
@Override
protected ResourceTable updateEntity(IBaseResource theResource, ResourceTable theEntity, boolean theUpdateHistory, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
boolean theUpdateVersion, Date theUpdateTime, RequestDetails theRequestDetails) {
ResourceTable retVal = super.updateEntity(theResource, theEntity, theUpdateHistory, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theRequestDetails);
protected ResourceTable updateEntity(IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
boolean theUpdateVersion, Date theUpdateTime) {
ResourceTable retVal = super.updateEntity(theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime);
CodeSystem cs = (CodeSystem) theResource;

View File

@ -31,7 +31,6 @@ import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.OperationOutcome;
import org.hl7.fhir.dstu3.model.OperationOutcome.IssueSeverity;
import org.hl7.fhir.dstu3.model.OperationOutcome.OperationOutcomeIssueComponent;
import org.hl7.fhir.instance.model.OperationOutcome.IssueType;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource;
@ -104,7 +103,7 @@ public class FhirResourceDaoDstu3<T extends IAnyResource> extends BaseHapiFhirRe
@Override
public MethodOutcome validate(T theResource, IIdType theId, String theRawResource, EncodingEnum theEncoding, ValidationModeEnum theMode, String theProfile, RequestDetails theRequestDetails) {
ActionRequestDetails requestDetails = new ActionRequestDetails(theId, null, theResource, getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, theResource, null, theId);
notifyInterceptors(RestOperationTypeEnum.VALIDATE, requestDetails);
if (theMode == ValidationModeEnum.DELETE) {

View File

@ -72,7 +72,7 @@ public class FhirResourceDaoPatientDstu3 extends FhirResourceDaoDstu3<Patient>im
@Override
public IBundleProvider patientInstanceEverything(HttpServletRequest theServletRequest, IIdType theId, IPrimitiveType<Integer> theCount, DateRangeParam theLastUpdated, SortSpec theSort, StringAndListParam theContent, StringAndListParam theNarrative, RequestDetails theRequestDetails) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName(), getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getResourceName(), null);
notifyInterceptors(RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE, requestDetails);
return doEverythingOperation(theId, theCount, theLastUpdated, theSort, theContent, theNarrative);
@ -81,7 +81,7 @@ public class FhirResourceDaoPatientDstu3 extends FhirResourceDaoDstu3<Patient>im
@Override
public IBundleProvider patientTypeEverything(HttpServletRequest theServletRequest, IPrimitiveType<Integer> theCount, DateRangeParam theLastUpdated, SortSpec theSort, StringAndListParam theContent, StringAndListParam theNarrative, RequestDetails theRequestDetails) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName(), getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getResourceName(), null);
notifyInterceptors(RestOperationTypeEnum.EXTENDED_OPERATION_TYPE, requestDetails);
return doEverythingOperation(null, theCount, theLastUpdated, theSort, theContent, theNarrative);

View File

@ -29,8 +29,6 @@ import org.springframework.scheduling.annotation.Scheduled;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoSearchParameter;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
public class FhirResourceDaoSearchParameterDstu3 extends FhirResourceDaoDstu3<SearchParameter>implements IFhirResourceDaoSearchParameter<SearchParameter> {
@ -50,10 +48,9 @@ public class FhirResourceDaoSearchParameterDstu3 extends FhirResourceDaoDstu3<Se
return;
}
RequestDetails requestDetails = new ServletRequestDetails();
int count = mySystemDao.performReindexingPass(100, requestDetails);
int count = mySystemDao.performReindexingPass(100);
for (int i = 0; i < 50 && count != 0; i++) {
count = mySystemDao.performReindexingPass(100, requestDetails);
count = mySystemDao.performReindexingPass(100);
try {
Thread.sleep(DateUtils.MILLIS_PER_SECOND);
} catch (InterruptedException e) {

View File

@ -64,7 +64,6 @@ import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.api.SortOrderEnum;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.server.Constants;
@ -257,7 +256,7 @@ public class FhirResourceDaoSubscriptionDstu3 extends FhirResourceDaoDstu3<Subsc
txTemplate.execute(new TransactionCallback<Void>() {
@Override
public Void doInTransaction(TransactionStatus theStatus) {
delete(subscriptionId, new ServletRequestDetails());
delete(subscriptionId, null);
return null;
}
});
@ -265,9 +264,9 @@ public class FhirResourceDaoSubscriptionDstu3 extends FhirResourceDaoDstu3<Subsc
}
@Override
protected ResourceTable updateEntity(IBaseResource theResource, ResourceTable theEntity, boolean theUpdateHistory, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
Date theUpdateTime, RequestDetails theRequestDetails) {
ResourceTable retVal = super.updateEntity(theResource, theEntity, theUpdateHistory, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theRequestDetails);
protected ResourceTable updateEntity(IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
Date theUpdateTime) {
ResourceTable retVal = super.updateEntity(theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime);
Subscription resource = (Subscription) theResource;
Long resourceId = theEntity.getId();
@ -316,8 +315,8 @@ public class FhirResourceDaoSubscriptionDstu3 extends FhirResourceDaoDstu3<Subsc
}
@Override
protected void validateResourceForStorage(Subscription theResource, ResourceTable theEntityToSave, RequestDetails theRequestDetails) {
super.validateResourceForStorage(theResource, theEntityToSave, theRequestDetails);
protected void validateResourceForStorage(Subscription theResource, ResourceTable theEntityToSave) {
super.validateResourceForStorage(theResource, theEntityToSave);
RuntimeResourceDefinition resDef = validateCriteriaAndReturnResourceDefinition(theResource);

View File

@ -26,6 +26,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.nio.file.FileVisitOption;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
@ -57,6 +58,7 @@ import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem.LookupCodeResult;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet;
import ca.uhn.fhir.jpa.util.LogicUtil;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.ElementUtil;
@ -71,8 +73,8 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3<ValueSet>
private IFhirResourceDaoCodeSystem<CodeSystem, CodeableConcept, Coding> myCodeSystemDao;
@Override
public ValueSet expand(IIdType theId, String theFilter) {
ValueSet source = myValidationSupport.fetchResource(getContext(), ValueSet.class, theId.getValue());
public ValueSet expand(IIdType theId, String theFilter, RequestDetails theRequestDetails) {
ValueSet source = read(theId, theRequestDetails);
return expand(source, theFilter);
}
@ -87,6 +89,7 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3<ValueSet>
ValueSetExpansionComponent expansion = outcome.getValueset().getExpansion();
ValueSet retVal = new ValueSet();
retVal.getMeta().setLastUpdated(new Date());
retVal.setExpansion(expansion);
return retVal;
}
@ -167,7 +170,7 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3<ValueSet>
@Override
public ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult validateCode(IPrimitiveType<String> theValueSetIdentifier, IIdType theId, IPrimitiveType<String> theCode,
IPrimitiveType<String> theSystem, IPrimitiveType<String> theDisplay, Coding theCoding, CodeableConcept theCodeableConcept) {
IPrimitiveType<String> theSystem, IPrimitiveType<String> theDisplay, Coding theCoding, CodeableConcept theCodeableConcept, RequestDetails theRequestDetails) {
List<IIdType> valueSetIds = Collections.emptyList();
@ -225,7 +228,7 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3<ValueSet>
// }
for (IIdType nextId : valueSetIds) {
ValueSet expansion = expand(nextId, null);
ValueSet expansion = expand(nextId, null, theRequestDetails);
List<ValueSetExpansionContainsComponent> contains = expansion.getExpansion().getContains();
ValidateCodeResult result = validateCodeIsInContains(contains, toStringOrNull(theSystem), toStringOrNull(theCode), theCoding, theCodeableConcept);
if (result != null) {

View File

@ -205,7 +205,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
@Override
public Meta metaGetOperation(RequestDetails theRequestDetails) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(null, null, getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails);
notifyInterceptors(RestOperationTypeEnum.META, requestDetails);
String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t)";
@ -264,7 +264,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
@Transactional(propagation = Propagation.REQUIRED)
@Override
public Bundle transaction(RequestDetails theRequestDetails, Bundle theRequest) {
ActionRequestDetails requestDetails = new ActionRequestDetails(null, "Bundle", theRequest, getContext(), theRequestDetails);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, theRequest, "Bundle", null);
notifyInterceptors(RestOperationTypeEnum.TRANSACTION, requestDetails);
String actionName = "Transaction";
@ -488,7 +488,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
IPrimitiveType<Date> deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get((IAnyResource) nextResource);
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
updateEntity(nextResource, nextOutcome.getEntity(), false, deletedTimestampOrNull, true, false, updateTime, theRequestDetails);
updateEntity(nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, false, updateTime);
}
myEntityManager.flush();

View File

@ -25,6 +25,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@ -39,6 +40,8 @@ import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;
@ -49,45 +52,54 @@ import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.lucene.analysis.core.WhitespaceTokenizerFactory;
import org.hibernate.search.annotations.Analyze;
import org.hibernate.search.annotations.Analyzer;
import org.hibernate.search.annotations.AnalyzerDef;
import org.hibernate.search.annotations.AnalyzerDefs;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Fields;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.Store;
import org.hibernate.search.annotations.TokenizerDef;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
import ca.uhn.fhir.jpa.search.DeferConceptIndexingInterceptor;
//@formatter:off
@Entity
@Indexed()
@Indexed(interceptor=DeferConceptIndexingInterceptor.class)
@Table(name="TRM_CONCEPT", uniqueConstraints= {
@UniqueConstraint(name="IDX_CONCEPT_CS_CODE", columnNames= {"CODESYSTEM_PID", "CODE"})
}, indexes= {
@Index(name = "IDX_CONCEPT_INDEXSTATUS", columnList="INDEX_STATUS")
})
@AnalyzerDefs({
@AnalyzerDef(name = "conceptParentPidsAnalyzer",
tokenizer = @TokenizerDef(factory = WhitespaceTokenizerFactory.class),
filters = {
})
})
//@formatter:on
public class TermConcept implements Serializable {
private static final int MAX_DESC_LENGTH = 400;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TermConcept.class);
private static final long serialVersionUID = 1L;
@OneToMany(fetch=FetchType.LAZY, mappedBy="myParent")
@OneToMany(fetch = FetchType.LAZY, mappedBy = "myParent", cascade= {})
private Collection<TermConceptParentChildLink> myChildren;
@Column(name="CODE", length=100, nullable=false)
@Fields({
@Field(name = "myCode", index = org.hibernate.search.annotations.Index.YES, store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = "exactAnalyzer")),
})
@Column(name = "CODE", length = 100, nullable = false)
@Fields({ @Field(name = "myCode", index = org.hibernate.search.annotations.Index.YES, store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = "exactAnalyzer")), })
private String myCode;
@ManyToOne()
@JoinColumn(name="CODESYSTEM_PID", referencedColumnName="PID", foreignKey=@ForeignKey(name="FK_CONCEPT_PID_CS_PID"))
@JoinColumn(name = "CODESYSTEM_PID", referencedColumnName = "PID", foreignKey = @ForeignKey(name = "FK_CONCEPT_PID_CS_PID"))
private TermCodeSystemVersion myCodeSystem;
@Column(name="CODESYSTEM_PID", insertable=false, updatable=false)
@Fields({
@Field(name="myCodeSystemVersionPid")
})
@Column(name = "CODESYSTEM_PID", insertable = false, updatable = false)
@Fields({ @Field(name = "myCodeSystemVersionPid") })
private long myCodeSystemVersionPid;
//@formatter:off
@ -102,21 +114,19 @@ public class TermConcept implements Serializable {
//@formatter:on
@Id()
@SequenceGenerator(name="SEQ_CONCEPT_PID", sequenceName="SEQ_CONCEPT_PID")
@GeneratedValue(strategy=GenerationType.AUTO, generator="SEQ_CONCEPT_PID")
@Column(name="PID")
@SequenceGenerator(name = "SEQ_CONCEPT_PID", sequenceName = "SEQ_CONCEPT_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CONCEPT_PID")
@Column(name = "PID")
private Long myId;
@Column(name = "INDEX_STATUS", nullable = true)
private Long myIndexStatus;
@Transient
@Fields({
@Field(name = "myParentPids", index = org.hibernate.search.annotations.Index.YES, store = Store.NO, analyze = Analyze.YES, analyzer = @Analyzer(definition = "standardAnalyzer")),
})
@Field(name = "myParentPids", index = org.hibernate.search.annotations.Index.YES, store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = "conceptParentPidsAnalyzer"))
private String myParentPids;
@OneToMany(cascade= {}, fetch=FetchType.LAZY, mappedBy="myChild")
@OneToMany(cascade = {}, fetch = FetchType.LAZY, mappedBy = "myChild")
private Collection<TermConceptParentChildLink> myParents;
public TermConcept() {
@ -155,7 +165,7 @@ public class TermConcept implements Serializable {
return true;
}
TermConcept obj = (TermConcept)theObj;
TermConcept obj = (TermConcept) theObj;
EqualsBuilder b = new EqualsBuilder();
b.append(myCodeSystem, obj.myCodeSystem);
@ -190,6 +200,10 @@ public class TermConcept implements Serializable {
return myIndexStatus;
}
public String getParentPidsAsString() {
return myParentPids;
}
public Collection<TermConceptParentChildLink> getParents() {
if (myParents == null) {
myParents = new ArrayList<TermConceptParentChildLink>();
@ -205,6 +219,28 @@ public class TermConcept implements Serializable {
return b.toHashCode();
}
private void parentPids(TermConcept theNextConcept, Set<Long> theParentPids) {
for (TermConceptParentChildLink nextParentLink : theNextConcept.getParents()) {
TermConcept parent = nextParentLink.getParent();
Long parentConceptId = parent.getId();
Validate.notNull(parentConceptId);
if (parent != null && theParentPids.add(parentConceptId)) {
parentPids(parent, theParentPids);
}
}
}
@PreUpdate
@PrePersist
public void prePersist() {
Set<Long> parentPids = new HashSet<Long>();
TermConcept entity = this;
parentPids(entity, parentPids);
entity.setParentPids(parentPids);
ourLog.trace("Code {}/{} has parents {}", entity.getId(), entity.getCode(), entity.getParentPidsAsString());
}
public void setCode(String theCode) {
myCode = theCode;
}
@ -237,6 +273,10 @@ public class TermConcept implements Serializable {
b.append(next);
}
if (b.length() == 0) {
b.append("NONE");
}
myParentPids = b.toString();
}
@ -244,5 +284,4 @@ public class TermConcept implements Serializable {
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append("code", myCode).append("display", myDisplay).build();
}
}

View File

@ -96,7 +96,55 @@ public class TermConceptParentChildLink implements Serializable {
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((myChild == null) ? 0 : myChild.hashCode());
result = prime * result + ((myCodeSystem == null) ? 0 : myCodeSystem.hashCode());
result = prime * result + ((myParent == null) ? 0 : myParent.hashCode());
result = prime * result + ((myRelationshipType == null) ? 0 : myRelationshipType.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TermConceptParentChildLink other = (TermConceptParentChildLink) obj;
if (myChild == null) {
if (other.myChild != null)
return false;
} else if (!myChild.equals(other.myChild))
return false;
if (myCodeSystem == null) {
if (other.myCodeSystem != null)
return false;
} else if (!myCodeSystem.equals(other.myCodeSystem))
return false;
if (myParent == null) {
if (other.myParent != null)
return false;
} else if (!myParent.equals(other.myParent))
return false;
if (myRelationshipType != other.myRelationshipType)
return false;
return true;
}
public enum RelationshipTypeEnum{
// ********************************************
// IF YOU ADD HERE MAKE SURE ORDER IS PRESERVED
ISA
}
public Long getId() {
return myPid;
}
}

View File

@ -53,7 +53,8 @@ public class BaseJpaResourceProviderValueSetDstu2 extends JpaResourceProviderDst
@IdParam(optional=true) IdDt theId,
@OperationParam(name="valueSet", min=0, max=1) ValueSet theValueSet,
@OperationParam(name="identifier", min=0, max=1) UriDt theIdentifier,
@OperationParam(name = "filter", min=0, max=1) StringDt theFilter) {
@OperationParam(name = "filter", min=0, max=1) StringDt theFilter,
RequestDetails theRequestDetails) {
//@formatter:on
boolean haveId = theId != null && theId.hasIdPart();
@ -72,7 +73,7 @@ public class BaseJpaResourceProviderValueSetDstu2 extends JpaResourceProviderDst
try {
IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt> dao = (IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt>) getDao();
if (haveId) {
return dao.expand(theId, toFilterString(theFilter));
return dao.expand(theId, toFilterString(theFilter), theRequestDetails);
} else if (haveIdentifier) {
return dao.expandByIdentifier(theIdentifier.getValue(), toFilterString(theFilter));
} else {
@ -155,14 +156,15 @@ public class BaseJpaResourceProviderValueSetDstu2 extends JpaResourceProviderDst
@OperationParam(name="system", min=0, max=1) UriDt theSystem,
@OperationParam(name="display", min=0, max=1) StringDt theDisplay,
@OperationParam(name="coding", min=0, max=1) CodingDt theCoding,
@OperationParam(name="codeableConcept", min=0, max=1) CodeableConceptDt theCodeableConcept
@OperationParam(name="codeableConcept", min=0, max=1) CodeableConceptDt theCodeableConcept,
RequestDetails theRequestDetails
) {
//@formatter:on
startRequest(theServletRequest);
try {
IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt> dao = (IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt>) getDao();
ValidateCodeResult result = dao.validateCode(theValueSetIdentifier, theId, theCode, theSystem, theDisplay, theCoding, theCodeableConcept);
ValidateCodeResult result = dao.validateCode(theValueSetIdentifier, theId, theCode, theSystem, theDisplay, theCoding, theCodeableConcept, theRequestDetails);
Parameters retVal = new Parameters();
retVal.addParameter().setName("result").setValue(new BooleanDt(result.isResult()));
if (isNotBlank(result.getMessage())) {

View File

@ -24,6 +24,9 @@ import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import org.hl7.fhir.instance.model.api.IBaseParameters;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.springframework.beans.factory.annotation.Required;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
@ -31,22 +34,36 @@ import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.rest.annotation.At;
import ca.uhn.fhir.rest.annotation.GetTags;
import ca.uhn.fhir.rest.annotation.History;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.annotation.Since;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.util.ParametersUtil;
public class BaseJpaSystemProvider<T, MT> extends BaseJpaProvider {
public static final String MARK_ALL_RESOURCES_FOR_REINDEXING = "$mark-all-resources-for-reindexing";
private IFhirSystemDao<T, MT> myDao;
public BaseJpaSystemProvider() {
// nothing
}
@Required
public void setDao(IFhirSystemDao<T, MT> theDao) {
myDao = theDao;
@GetTags
public TagList getAllTagsOnServer(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
startRequest(theRequest);
try {
return myDao.getAllTags(theRequestDetails);
} finally {
endRequest(theRequest);
}
}
protected IFhirSystemDao<T, MT> getDao() {
return myDao;
}
@History
@ -60,18 +77,9 @@ public class BaseJpaSystemProvider<T, MT> extends BaseJpaProvider {
}
}
protected IFhirSystemDao<T, MT> getDao() {
return myDao;
}
@GetTags
public TagList getAllTagsOnServer(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
startRequest(theRequest);
try {
return myDao.getAllTags(theRequestDetails);
} finally {
endRequest(theRequest);
}
@Required
public void setDao(IFhirSystemDao<T, MT> theDao) {
myDao = theDao;
}
}

View File

@ -0,0 +1,30 @@
package ca.uhn.fhir.jpa.provider;
import org.hl7.fhir.instance.model.api.IBaseParameters;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.util.ParametersUtil;
public abstract class BaseJpaSystemProviderDstu2Plus<T, MT> extends BaseJpaSystemProvider<T, MT> {
//@formatter:off
@Operation(name=MARK_ALL_RESOURCES_FOR_REINDEXING, idempotent=true, returnParameters= {
@OperationParam(name="status")
})
//@formatter:on
public IBaseResource markAllResourcesForReindexing() {
int count = getDao().markAllResourcesForReindexing();
IBaseParameters retVal = ParametersUtil.newInstance(getContext());
IPrimitiveType<?> string = ParametersUtil.createString(getContext(), "Marked " + count + " resources");
ParametersUtil.addParameterToParameters(getContext(), retVal, string, "status");
return retVal;
}
}

View File

@ -50,7 +50,7 @@ import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
public class JpaSystemProviderDstu2 extends BaseJpaSystemProvider<Bundle, MetaDt> {
public class JpaSystemProviderDstu2 extends BaseJpaSystemProviderDstu2Plus<Bundle, MetaDt> {
@Autowired()
@Qualifier("mySystemDaoDstu2")
@ -169,18 +169,6 @@ public class JpaSystemProviderDstu2 extends BaseJpaSystemProvider<Bundle, MetaDt
return retVal;
}
//@formatter:off
@Operation(name="$mark-all-resources-for-reindexing", idempotent=true, returnParameters= {
@OperationParam(name="count", type=IntegerDt.class)
})
//@formatter:on
public Parameters markAllResourcesForReindexing() {
int count = mySystemDao.markAllResourcesForReindexing();
Parameters retVal = new Parameters();
retVal.addParameter().setName("count").setValue(new IntegerDt(count));
return retVal;
}
//@formatter:off
@Operation(name="$meta", idempotent=true, returnParameters= {

View File

@ -39,6 +39,7 @@ import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDstu3<ValueSet> {
@ -50,7 +51,8 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst
@IdParam(optional=true) IdType theId,
@OperationParam(name="valueSet", min=0, max=1) ValueSet theValueSet,
@OperationParam(name="identifier", min=0, max=1) UriType theIdentifier,
@OperationParam(name = "filter", min=0, max=1) StringType theFilter) {
@OperationParam(name = "filter", min=0, max=1) StringType theFilter,
RequestDetails theRequestDetails) {
//@formatter:on
boolean haveId = theId != null && theId.hasIdPart();
@ -69,7 +71,7 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst
try {
IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao();
if (haveId) {
return dao.expand(theId, toFilterString(theFilter));
return dao.expand(theId, toFilterString(theFilter), theRequestDetails);
} else if (haveIdentifier) {
return dao.expandByIdentifier(theIdentifier.getValue(), toFilterString(theFilter));
} else {
@ -102,14 +104,15 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst
@OperationParam(name="system", min=0, max=1) UriType theSystem,
@OperationParam(name="display", min=0, max=1) StringType theDisplay,
@OperationParam(name="coding", min=0, max=1) Coding theCoding,
@OperationParam(name="codeableConcept", min=0, max=1) CodeableConcept theCodeableConcept
@OperationParam(name="codeableConcept", min=0, max=1) CodeableConcept theCodeableConcept,
RequestDetails theRequestDetails
) {
//@formatter:on
startRequest(theServletRequest);
try {
IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao();
ValidateCodeResult result = dao.validateCode(theValueSetIdentifier, theId, theCode, theSystem, theDisplay, theCoding, theCodeableConcept);
ValidateCodeResult result = dao.validateCode(theValueSetIdentifier, theId, theCode, theSystem, theDisplay, theCoding, theCodeableConcept, theRequestDetails);
Parameters retVal = new Parameters();
retVal.addParameter().setName("result").setValue(new BooleanType(result.isResult()));
if (isNotBlank(result.getMessage())) {

View File

@ -41,7 +41,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl.Suggestion;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
import ca.uhn.fhir.jpa.provider.BaseJpaSystemProvider;
import ca.uhn.fhir.jpa.provider.BaseJpaSystemProviderDstu2Plus;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
@ -51,7 +51,7 @@ import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
public class JpaSystemProviderDstu3 extends BaseJpaSystemProvider<Bundle, Meta> {
public class JpaSystemProviderDstu3 extends BaseJpaSystemProviderDstu2Plus<Bundle, Meta> {
@Autowired()
@Qualifier("mySystemDaoDstu3")
@ -170,19 +170,6 @@ public class JpaSystemProviderDstu3 extends BaseJpaSystemProvider<Bundle, Meta>
return retVal;
}
//@formatter:off
@Operation(name="$mark-all-resources-for-reindexing", idempotent=true, returnParameters= {
@OperationParam(name="count", type=IntegerType.class)
})
//@formatter:on
public Parameters markAllResourcesForReindexing() {
int count = mySystemDao.markAllResourcesForReindexing();
Parameters retVal = new Parameters();
retVal.addParameter().setName("count").setValue(new IntegerType(count));
return retVal;
}
//@formatter:off
@Operation(name="$meta", idempotent=true, returnParameters= {
@OperationParam(name="return", type=Meta.class)

View File

@ -48,13 +48,15 @@ import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class TerminologyUploaderProviderDstu3 extends BaseJpaProvider {
public static final String UPLOAD_EXTERNAL_CODE_SYSTEM = "$upload-external-code-system";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TerminologyUploaderProviderDstu3.class);
@Autowired
private IHapiTerminologyLoaderSvc myTerminologyLoaderSvc;
//@formatter:off
@Operation(name = "$upload-external-code-system", idempotent = false, returnParameters= {
@Operation(name = UPLOAD_EXTERNAL_CODE_SYSTEM, idempotent = false, returnParameters= {
@OperationParam(name="conceptCount", type=IntegerType.class, min=1)
})
public Parameters uploadExternalCodeSystem(

View File

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

View File

@ -146,7 +146,7 @@ public class SubscriptionWebsocketHandlerDstu2 extends TextWebSocketHandler impl
public void closing() {
ourLog.info("Deleting subscription {}", mySubscriptionId);
try {
mySubscriptionDao.delete(mySubscriptionId, new ServletRequestDetails());
mySubscriptionDao.delete(mySubscriptionId, null);
} catch (Exception e) {
handleFailure(e);
}
@ -233,7 +233,7 @@ public class SubscriptionWebsocketHandlerDstu2 extends TextWebSocketHandler impl
}
try {
Subscription subscription = mySubscriptionDao.read(id, new ServletRequestDetails());
Subscription subscription = mySubscriptionDao.read(id, null);
mySubscriptionPid = mySubscriptionDao.getSubscriptionTablePidForSubscriptionResource(id);
mySubscriptionId = subscription.getIdElement();
myState = new BoundStaticSubscipriptionState(theSession);
@ -270,7 +270,7 @@ public class SubscriptionWebsocketHandlerDstu2 extends TextWebSocketHandler impl
}
}
IIdType id = mySubscriptionDao.create(subscription, new ServletRequestDetails()).getId();
IIdType id = mySubscriptionDao.create(subscription, null).getId();
mySubscriptionPid = mySubscriptionDao.getSubscriptionTablePidForSubscriptionResource(id);
mySubscriptionId = subscription.getIdElement();

View File

@ -146,7 +146,7 @@ public class SubscriptionWebsocketHandlerDstu3 extends TextWebSocketHandler impl
public void closing() {
ourLog.info("Deleting subscription {}", mySubscriptionId);
try {
mySubscriptionDao.delete(mySubscriptionId, new ServletRequestDetails());
mySubscriptionDao.delete(mySubscriptionId, null);
} catch (Exception e) {
handleFailure(e);
}
@ -233,7 +233,7 @@ public class SubscriptionWebsocketHandlerDstu3 extends TextWebSocketHandler impl
}
try {
Subscription subscription = mySubscriptionDao.read(id, new ServletRequestDetails());
Subscription subscription = mySubscriptionDao.read(id, null);
mySubscriptionPid = mySubscriptionDao.getSubscriptionTablePidForSubscriptionResource(id);
mySubscriptionId = subscription.getIdElement();
myState = new BoundStaticSubscipriptionState(theSession);
@ -270,7 +270,7 @@ public class SubscriptionWebsocketHandlerDstu3 extends TextWebSocketHandler impl
}
}
IIdType id = mySubscriptionDao.create(subscription, new ServletRequestDetails()).getId();
IIdType id = mySubscriptionDao.create(subscription, null).getId();
mySubscriptionPid = mySubscriptionDao.getSubscriptionTablePidForSubscriptionResource(id);
mySubscriptionId = subscription.getIdElement();

View File

@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.term;
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.IdentityHashMap;
@ -32,10 +33,17 @@ import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
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.TransactionTemplate;
import com.google.common.base.Stopwatch;
@ -50,6 +58,8 @@ 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.entity.TermConceptParentChildLink.RelationshipTypeEnum;
import ca.uhn.fhir.jpa.util.StopWatch;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.ObjectUtil;
@ -85,6 +95,7 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
protected EntityManager myEntityManager;
private boolean myProcessDeferred = true;
private long myNextReindexPass;
private boolean addToSet(Set<TermConcept> theSetToPopulate, TermConcept theConcept) {
boolean retVal = theSetToPopulate.add(theConcept);
@ -209,15 +220,6 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
return cs;
}
private void parentPids(TermConcept theNextConcept, Set<Long> theParentPids) {
for (TermConceptParentChildLink nextParentLink : theNextConcept.getParents()){
TermConcept parent = nextParentLink.getParent();
if (parent != null && theParentPids.add(parent.getId())) {
parentPids(parent, theParentPids);
}
}
}
private void persistChildren(TermConcept theConcept, TermCodeSystemVersion theCodeSystem, IdentityHashMap<TermConcept, Object> theConceptsStack, int theTotalConcepts) {
if (theConceptsStack.put(theConcept, PLACEHOLDER_OBJECT) != null) {
return;
@ -231,12 +233,8 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
theConcept.setCodeSystem(theCodeSystem);
theConcept.setIndexStatus(BaseHapiFhirDao.INDEX_STATUS_INDEXED);
Set<Long> parentPids = new HashSet<Long>();
parentPids(theConcept, parentPids);
theConcept.setParentPids(parentPids);
if (theConceptsStack.size() <= myDaoConfig.getDeferIndexingForCodesystemsOfSize()) {
myConceptDao.save(theConcept);
saveConcept(theConcept);
} else {
myConceptsToSaveLater.add(theConcept);
}
@ -247,7 +245,7 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
for (TermConceptParentChildLink next : theConcept.getChildren()) {
if (theConceptsStack.size() <= myDaoConfig.getDeferIndexingForCodesystemsOfSize()) {
myConceptParentChildLinkDao.save(next);
saveConceptLink(next);
} else {
myConceptLinksToSaveLater.add(next);
}
@ -255,6 +253,44 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
}
private void saveConceptLink(TermConceptParentChildLink next) {
if (next.getId() == null) {
myConceptParentChildLinkDao.save(next);
}
}
private int saveConcept(TermConcept theConcept) {
int retVal = 0;
retVal += ensureParentsSaved(theConcept.getParents());
if (theConcept.getId() == null || theConcept.getIndexStatus() == null) {
retVal++;
theConcept.setIndexStatus(BaseHapiFhirDao.INDEX_STATUS_INDEXED);
myConceptDao.saveAndFlush(theConcept);
}
ourLog.trace("Saved {} and got PID {}", theConcept.getCode(), theConcept.getId());
return retVal;
}
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();
retVal += ensureParentsSaved(nextParent.getParents());
if (nextParent.getId() == null) {
myConceptDao.saveAndFlush(nextParent);
retVal++;
ourLog.debug("Saved parent code {} and got id {}", nextParent.getCode(), nextParent.getId());
}
}
}
return retVal;
}
private void populateVersion(TermConcept theNext, TermCodeSystemVersion theCodeSystemVersion) {
if (theNext.getCodeSystem() != null) {
return;
@ -269,18 +305,25 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
@Transactional(propagation=Propagation.REQUIRED)
@Override
public synchronized void saveDeferred() {
if (!myProcessDeferred || ((myConceptsToSaveLater.isEmpty() && myConceptLinksToSaveLater.isEmpty()))) {
if (!myProcessDeferred) {
return;
} else if (myConceptsToSaveLater.isEmpty() && myConceptLinksToSaveLater.isEmpty()) {
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);
myConceptDao.save(next);
codeCount++;
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) {
@ -288,12 +331,54 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
ourLog.info("Saving {} deferred concept relationships...", count);
while (relCount < count && myConceptLinksToSaveLater.size() > 0) {
TermConceptParentChildLink next = myConceptLinksToSaveLater.remove(0);
myConceptParentChildLinkDao.save(next);
saveConceptLink(next);
relCount++;
}
}
ourLog.info("Saved {} deferred concepts ({} remain) and {} deferred relationships ({} remain)", new Object[] {codeCount, myConceptsToSaveLater.size(), relCount, myConceptLinksToSaveLater.size()});
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");
}
}
@Autowired
private PlatformTransactionManager myTransactionMgr;
private void processReindexing() {
if (System.currentTimeMillis() < myNextReindexPass) {
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> resources = myConceptDao.findResourcesRequiringReindexing(new PageRequest(0, maxResult));
if (resources.hasContent() == false) {
myNextReindexPass = System.currentTimeMillis() + DateUtils.MILLIS_PER_MINUTE;
return;
}
ourLog.info("Indexing {} / {} concepts", resources.getContent().size(), resources.getTotalElements());
int count = 0;
StopWatch stopwatch = new StopWatch();
for (TermConcept resourceTable : resources) {
saveConcept(resourceTable);
count++;
}
ourLog.info("Indexed {} / {} concepts in {}ms - Avg {}ms / resource", new Object[] { count, resources.getContent().size(), stopwatch.getMillis(), stopwatch.getMillisPerOperation(count) });
}
});
}
@Override

View File

@ -29,6 +29,7 @@ import java.util.List;
import java.util.Set;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.QueryWrapperFilter;
import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.FullTextQuery;
import org.hibernate.search.query.dsl.BooleanJunction;
@ -78,56 +79,38 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvc implements I
@Autowired
private ValueSetExpander myValueSetExpander;
@Override
public List<VersionIndependentConcept> expandValueSet(String theValueSet) {
ValueSet source = new ValueSet();
source.getCompose().addImport(theValueSet);
try {
ArrayList<VersionIndependentConcept> retVal = new ArrayList<VersionIndependentConcept>();
ValueSetExpansionOutcome outcome = myValueSetExpander.expand(source);
for (ValueSetExpansionContainsComponent next : outcome.getValueset().getExpansion().getContains()) {
retVal.add(new VersionIndependentConcept(next.getSystem(), next.getCode()));
}
return retVal;
} catch (Exception e) {
throw new InternalErrorException(e);
private void addCodeIfNotAlreadyAdded(String system, ValueSetExpansionComponent retVal, Set<String> addedCodes, TermConcept nextConcept) {
if (addedCodes.add(nextConcept.getCode())) {
ValueSetExpansionContainsComponent contains = retVal.addContains();
contains.setCode(nextConcept.getCode());
contains.setSystem(system);
contains.setDisplay(nextConcept.getDisplay());
}
}
@Override
@Transactional(propagation=Propagation.REQUIRED)
public void storeNewCodeSystemVersion(String theSystem, TermCodeSystemVersion theCodeSystemVersion, RequestDetails theRequestDetails) {
CodeSystem cs = new org.hl7.fhir.dstu3.model.CodeSystem();
cs.setUrl(theSystem);
cs.setContent(CodeSystemContentMode.NOTPRESENT);
DaoMethodOutcome createOutcome = myCodeSystemResourceDao.create(cs, "CodeSystem?url=" + UrlUtil.escape(theSystem), theRequestDetails);
IIdType csId = createOutcome.getId().toUnqualifiedVersionless();
if (createOutcome.getCreated() != Boolean.TRUE) {
CodeSystem existing = myCodeSystemResourceDao.read(csId, theRequestDetails);
csId = myCodeSystemResourceDao.update(existing, theRequestDetails).getId();
ourLog.info("Created new version of CodeSystem, got ID: {}", csId.toUnqualified().getValue());
}
ResourceTable resource = (ResourceTable) myCodeSystemResourceDao.readEntity(csId);
Long codeSystemResourcePid = resource.getId();
ourLog.info("CodeSystem resource has ID: {}", csId.getValue());
theCodeSystemVersion.setResource(resource);
theCodeSystemVersion.setResourceVersionId(resource.getVersion());
super.storeNewCodeSystemVersion(codeSystemResourcePid, theSystem, theCodeSystemVersion);
private void addDisplayFilterExact(QueryBuilder qb, BooleanJunction<?> bool, ConceptSetFilterComponent nextFilter) {
bool.must(qb.phrase().onField("myDisplay").sentence(nextFilter.getValue()).createQuery());
}
private void addDisplayFilterInexact(QueryBuilder qb, BooleanJunction<?> bool, ConceptSetFilterComponent nextFilter) {
//@formatter:off
Query textQuery = qb
.phrase()
.withSlop(2)
.onField("myDisplay").boostedTo(4.0f)
.andField("myDisplayEdgeNGram").boostedTo(2.0f)
//.andField("myDisplayNGram").boostedTo(1.0f)
//.andField("myDisplayPhonetic").boostedTo(0.5f)
.sentence(nextFilter.getValue().toLowerCase()).createQuery();
bool.must(textQuery);
//@formatter:on
}
@Override
public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
String system = theInclude.getSystem();
ourLog.info("Starting expansion around code system: {}", system);
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(system);
TermCodeSystemVersion csv = cs.getCurrentVersion();
@ -167,27 +150,40 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvc implements I
bool.must(qb.keyword().onField("myCodeSystemVersionPid").matching(csv.getPid()).createQuery());
for (ConceptSetFilterComponent nextFilter : theInclude.getFilter()) {
if (nextFilter.getProperty().equals("display") && nextFilter.getOp() == FilterOperator.EQUAL) {
if (isNotBlank(nextFilter.getValue())) {
bool.must(qb.phrase().onField("myDisplay").sentence(nextFilter.getValue()).createQuery());
}
} else if (nextFilter.getOp() == FilterOperator.ISA) {
if (isNotBlank(nextFilter.getValue())) {
if (isNotBlank(nextFilter.getValue())) {
if (nextFilter.getProperty().equals("display:exact") && nextFilter.getOp() == FilterOperator.EQUAL) {
addDisplayFilterExact(qb, bool, nextFilter);
} else if (nextFilter.getProperty().equals("display") && nextFilter.getOp() == FilterOperator.EQUAL) {
if (nextFilter.getValue().trim().contains(" ")) {
addDisplayFilterExact(qb, bool, nextFilter);
} else {
addDisplayFilterInexact(qb, bool, nextFilter);
}
} else if ((nextFilter.getProperty().equals("concept") || nextFilter.getProperty().equals("code")) && nextFilter.getOp() == FilterOperator.ISA) {
TermConcept code = super.findCode(system, nextFilter.getValue());
if (code == null) {
throw new InvalidRequestException("Invalid filter criteria - code does not exist: {" + system + "}" + nextFilter.getValue());
}
ourLog.info(" * Filtering on codes with a parent of {}/{}/{}", code.getId(), code.getCode(), code.getDisplay());
bool.must(qb.keyword().onField("myParentPids").matching("" + code.getId()).createQuery());
} else {
throw new InvalidRequestException("Unknown filter property[" + nextFilter + "] + op[" + nextFilter.getOpElement().getValueAsString() + "]");
}
} else {
throw new InvalidRequestException("Unknown filter property[" + nextFilter + "] + op[" + nextFilter.getOpElement().getValueAsString() + "]");
}
}
Query luceneQuery = bool.createQuery();
FullTextQuery jpaQuery = em.createFullTextQuery(luceneQuery, TermConcept.class);
jpaQuery.setMaxResults(1000);
@SuppressWarnings("unchecked")
List<TermConcept> result = jpaQuery.getResultList();
for (TermConcept nextConcept : result) {
addCodeIfNotAlreadyAdded(system, retVal, addedCodes, nextConcept);
}
retVal.setTotal(jpaQuery.getResultSize());
}
if (!haveIncludeCriteria) {
@ -197,18 +193,28 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvc implements I
}
}
retVal.setTotal(retVal.getContains().size());
return retVal;
}
private void addCodeIfNotAlreadyAdded(String system, ValueSetExpansionComponent retVal, Set<String> addedCodes, TermConcept nextConcept) {
if (addedCodes.add(nextConcept.getCode())) {
ValueSetExpansionContainsComponent contains = retVal.addContains();
contains.setCode(nextConcept.getCode());
contains.setSystem(system);
contains.setDisplay(nextConcept.getDisplay());
@Override
public List<VersionIndependentConcept> expandValueSet(String theValueSet) {
ValueSet source = new ValueSet();
source.getCompose().addImport(theValueSet);
try {
ArrayList<VersionIndependentConcept> retVal = new ArrayList<VersionIndependentConcept>();
ValueSetExpansionOutcome outcome = myValueSetExpander.expand(source);
for (ValueSetExpansionContainsComponent next : outcome.getValueset().getExpansion().getContains()) {
retVal.add(new VersionIndependentConcept(next.getSystem(), next.getCode()));
}
return retVal;
} catch (Exception e) {
throw new InternalErrorException(e);
}
}
@Override
@ -238,6 +244,33 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvc implements I
return super.supportsSystem(theSystem);
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void storeNewCodeSystemVersion(String theSystem, TermCodeSystemVersion theCodeSystemVersion, RequestDetails theRequestDetails) {
CodeSystem cs = new org.hl7.fhir.dstu3.model.CodeSystem();
cs.setUrl(theSystem);
cs.setContent(CodeSystemContentMode.NOTPRESENT);
DaoMethodOutcome createOutcome = myCodeSystemResourceDao.create(cs, "CodeSystem?url=" + UrlUtil.escape(theSystem), theRequestDetails);
IIdType csId = createOutcome.getId().toUnqualifiedVersionless();
if (createOutcome.getCreated() != Boolean.TRUE) {
CodeSystem existing = myCodeSystemResourceDao.read(csId, theRequestDetails);
csId = myCodeSystemResourceDao.update(existing, theRequestDetails).getId();
ourLog.info("Created new version of CodeSystem, got ID: {}", csId.toUnqualified().getValue());
}
ResourceTable resource = (ResourceTable) myCodeSystemResourceDao.readEntity(csId);
Long codeSystemResourcePid = resource.getId();
ourLog.info("CodeSystem resource has ID: {}", csId.getValue());
theCodeSystemVersion.setResource(resource);
theCodeSystemVersion.setResourceVersionId(resource.getVersion());
super.storeNewCodeSystemVersion(codeSystemResourcePid, theSystem, theCodeSystemVersion);
}
@CoverageIgnore
@Override
public CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay) {

View File

@ -24,15 +24,12 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@ -47,7 +44,6 @@ import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.apache.commons.csv.QuoteMode;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
@ -102,6 +98,8 @@ public class TerminologyLoaderSvc implements IHapiTerminologyLoaderSvc {
}
ourLog.info(b.toString(), theConcept.getCode());
childIter.remove();
nextChild.getParents().remove(next);
} else {
dropCircularRefs(nextChild, theChain, theCode2concept, theCircularCounter);
}

View File

@ -32,4 +32,14 @@ public class StopWatch {
return retVal;
}
public long getMillis() {
long now = System.currentTimeMillis();
long retVal = now - myStarted;
return retVal;
}
public double getMillisPerOperation(int theNumOperations) {
return ((double)getMillis()) / Math.max(1.0, theNumOperations);
}
}

View File

@ -101,7 +101,7 @@ public class SubscriptionsRequireManualActivationInterceptorDstu2 extends Interc
if (requestId != null && requestId.hasIdPart()) {
Subscription existing;
try {
existing = myDao.read(requestId, new ServletRequestDetails());
existing = myDao.read(requestId, null);
SubscriptionStatusEnum existingStatus = existing.getStatusElement().getValueAsEnum();
if (existingStatus != newStatus) {
verifyActiveStatus(subscription, newStatus, existingStatus);

View File

@ -38,7 +38,6 @@ import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.CoverageIgnore;
/**
@ -102,7 +101,7 @@ public class SubscriptionsRequireManualActivationInterceptorDstu3 extends Interc
if (requestId != null && requestId.hasIdPart()) {
Subscription existing;
try {
existing = myDao.read(requestId, new ServletRequestDetails());
existing = myDao.read(requestId, null);
SubscriptionStatus existingStatus = existing.getStatusElement().getValue();
if (existingStatus != newStatus) {
verifyActiveStatus(subscription, newStatus, existingStatus);

View File

@ -39,7 +39,6 @@ import ca.uhn.fhir.model.dstu2.valueset.SubscriptionStatusEnum;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.TestUtil;
public class FhirResourceDaoDstu2SubscriptionTest extends BaseJpaDstu2Test {
@ -390,7 +389,7 @@ public class FhirResourceDaoDstu2SubscriptionTest extends BaseJpaDstu2Test {
*/
mySystemDao.markAllResourcesForReindexing();
mySystemDao.performReindexingPass(100, mySrd);
mySystemDao.performReindexingPass(100);
assertEquals(0, mySubscriptionDao.pollForNewUndeliveredResources());

View File

@ -16,7 +16,6 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.transaction.annotation.Transactional;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult;
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
@ -25,7 +24,6 @@ import ca.uhn.fhir.model.primitive.CodeDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.TestUtil;
public class FhirResourceDaoValueSetDstu2Test extends BaseJpaDstu2Test {
@ -58,7 +56,7 @@ public class FhirResourceDaoValueSetDstu2Test extends BaseJpaDstu2Test {
StringDt display = null;
CodingDt coding = null;
CodeableConceptDt codeableConcept = null;
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
assertFalse(result.isResult());
}
@ -71,7 +69,7 @@ public class FhirResourceDaoValueSetDstu2Test extends BaseJpaDstu2Test {
StringDt display = null;
CodingDt coding = null;
CodeableConceptDt codeableConcept = null;
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
assertTrue(result.isResult());
assertEquals("Systolic blood pressure--expiration", result.getDisplay());
}
@ -85,7 +83,7 @@ public class FhirResourceDaoValueSetDstu2Test extends BaseJpaDstu2Test {
StringDt display = null;
CodingDt coding = null;
CodeableConceptDt codeableConcept = null;
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
assertTrue(result.isResult());
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
}
@ -99,7 +97,7 @@ public class FhirResourceDaoValueSetDstu2Test extends BaseJpaDstu2Test {
StringDt display = new StringDt("Systolic blood pressure at First encounterXXXX");
CodingDt coding = null;
CodeableConceptDt codeableConcept = null;
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
assertFalse(result.isResult());
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
}
@ -113,7 +111,7 @@ public class FhirResourceDaoValueSetDstu2Test extends BaseJpaDstu2Test {
StringDt display = new StringDt("Systolic blood pressure at First encounter");
CodingDt coding = null;
CodeableConceptDt codeableConcept = null;
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
assertTrue(result.isResult());
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
}
@ -127,7 +125,7 @@ public class FhirResourceDaoValueSetDstu2Test extends BaseJpaDstu2Test {
StringDt display = null;
CodingDt coding = null;
CodeableConceptDt codeableConcept = new CodeableConceptDt("http://loinc.org", "11378-7");
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
assertTrue(result.isResult());
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
}
@ -141,7 +139,7 @@ public class FhirResourceDaoValueSetDstu2Test extends BaseJpaDstu2Test {
StringDt display = null;
CodingDt coding = null;
CodeableConceptDt codeableConcept = null;
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
assertTrue(result.isResult());
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
}
@ -150,7 +148,7 @@ public class FhirResourceDaoValueSetDstu2Test extends BaseJpaDstu2Test {
public void testExpandById() throws IOException {
String resp;
ValueSet expanded = myValueSetDao.expand(myExtensionalVsId, null);
ValueSet expanded = myValueSetDao.expand(myExtensionalVsId, null, mySrd);
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
// @formatter:off
@ -175,7 +173,7 @@ public class FhirResourceDaoValueSetDstu2Test extends BaseJpaDstu2Test {
* Filter with display name
*/
expanded = myValueSetDao.expand(myExtensionalVsId, ("systolic"));
expanded = myValueSetDao.expand(myExtensionalVsId, ("systolic"), mySrd);
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
//@formatter:off
@ -188,7 +186,7 @@ public class FhirResourceDaoValueSetDstu2Test extends BaseJpaDstu2Test {
* Filter with code
*/
expanded = myValueSetDao.expand(myExtensionalVsId, ("11378"));
expanded = myValueSetDao.expand(myExtensionalVsId, ("11378"), mySrd);
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
//@formatter:off

View File

@ -101,7 +101,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2SystemTest {
});
assertEquals(null, entity.getIndexStatus());
mySystemDao.performReindexingPass(null, mySrd);
mySystemDao.performReindexingPass(null);
entity = new TransactionTemplate(myTxManager).execute(new TransactionCallback<ResourceTable>() {
@Override
@ -112,7 +112,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2SystemTest {
assertEquals(Long.valueOf(1), entity.getIndexStatus());
// Just make sure this doesn't cause a choke
mySystemDao.performReindexingPass(100000, mySrd);
mySystemDao.performReindexingPass(100000);
// Try making the resource unparseable
@ -134,7 +134,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2SystemTest {
}
});
mySystemDao.performReindexingPass(null, mySrd);
mySystemDao.performReindexingPass(null);
entity = new TransactionTemplate(myTxManager).execute(new TransactionCallback<ResourceTable>() {
@Override

View File

@ -81,7 +81,7 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
}
private ServletRequestDetails mockSrd() {
return new ServletRequestDetails();
return mySrd;
}
@Test

View File

@ -390,7 +390,7 @@ public class FhirResourceDaoDstu3SubscriptionTest extends BaseJpaDstu3Test {
*/
mySystemDao.markAllResourcesForReindexing();
mySystemDao.performReindexingPass(100, mySrd);
mySystemDao.performReindexingPass(100);
assertEquals(0, mySubscriptionDao.pollForNewUndeliveredResources());

View File

@ -1,6 +1,7 @@
package ca.uhn.fhir.jpa.dao.dstu3;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsStringIgnoringCase;
import static org.hamcrest.Matchers.empty;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
@ -37,21 +38,123 @@ import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.param.TokenParamModifier;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.TestUtil;
public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
private static final String URL_MY_VALUE_SET = "http://example.com/my_value_set";
private static final String URL_MY_CODE_SYSTEM = "http://example.com/my_code_system";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3TerminologyTest.class);
public static final String URL_MY_CODE_SYSTEM = "http://example.com/my_code_system";
public static final String URL_MY_VALUE_SET = "http://example.com/my_value_set";
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
@After
public void after() {
myDaoConfig.setDeferIndexingForCodesystemsOfSize(new DaoConfig().getDeferIndexingForCodesystemsOfSize());
}
@Before
public void before() {
myDaoConfig.setMaximumExpansionSize(5000);
}
private CodeSystem createExternalCs() {
CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
ResourceTable table = myResourceTableDao.findOne(id.getIdPartAsLong());
TermCodeSystemVersion cs = new TermCodeSystemVersion();
cs.setResource(table);
cs.setResourceVersionId(table.getVersion());
TermConcept parentA = new TermConcept(cs, "ParentA").setDisplay("Parent A");
cs.getConcepts().add(parentA);
TermConcept childAA = new TermConcept(cs, "childAA").setDisplay("Child AA");
parentA.addChild(childAA, RelationshipTypeEnum.ISA);
TermConcept childAAA = new TermConcept(cs, "childAAA").setDisplay("Child AAA");
childAA.addChild(childAAA, RelationshipTypeEnum.ISA);
TermConcept childAAB = new TermConcept(cs, "childAAB").setDisplay("Child AAB");
childAA.addChild(childAAB, RelationshipTypeEnum.ISA);
TermConcept childAB = new TermConcept(cs, "childAB").setDisplay("Child AB");
parentA.addChild(childAB, RelationshipTypeEnum.ISA);
TermConcept parentB = new TermConcept(cs, "ParentB").setDisplay("Parent B");
cs.getConcepts().add(parentB);
TermConcept childBA = new TermConcept(cs, "childBA").setDisplay("Child BA");
childBA.addChild(childAAB, RelationshipTypeEnum.ISA);
parentB.addChild(childBA, RelationshipTypeEnum.ISA);
TermConcept parentC = new TermConcept(cs, "ParentC").setDisplay("Parent C");
cs.getConcepts().add(parentC);
TermConcept childCA = new TermConcept(cs, "childCA").setDisplay("Child CA");
parentC.addChild(childCA, RelationshipTypeEnum.ISA);
myTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM, cs);
return codeSystem;
}
private void createExternalCsAndLocalVs() {
CodeSystem codeSystem = createExternalCs();
createLocalVs(codeSystem);
}
private void createLocalCsAndVs() {
//@formatter:off
CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
codeSystem.setContent(CodeSystemContentMode.COMPLETE);
codeSystem
.addConcept().setCode("A").setDisplay("Code A")
.addConcept(new ConceptDefinitionComponent().setCode("AA").setDisplay("Code AA")
.addConcept(new ConceptDefinitionComponent().setCode("AAA").setDisplay("Code AAA"))
)
.addConcept(new ConceptDefinitionComponent().setCode("AB").setDisplay("Code AB"));
codeSystem
.addConcept().setCode("B").setDisplay("Code B")
.addConcept(new ConceptDefinitionComponent().setCode("BA").setDisplay("Code BA"))
.addConcept(new ConceptDefinitionComponent().setCode("BB").setDisplay("Code BB"));
//@formatter:on
myCodeSystemDao.create(codeSystem, mySrd);
createLocalVs(codeSystem);
}
private void createLocalVs(CodeSystem codeSystem) {
ValueSet valueSet = new ValueSet();
valueSet.setUrl(URL_MY_VALUE_SET);
valueSet.getCompose().addInclude().setSystem(codeSystem.getUrl());
myValueSetDao.create(valueSet, mySrd);
}
@Test
public void testCodeSystemCreateDuplicateFails() {
CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
codeSystem.setContent(CodeSystemContentMode.COMPLETE);
IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
codeSystem = new CodeSystem();
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
codeSystem.setContent(CodeSystemContentMode.COMPLETE);
try {
myCodeSystemDao.create(codeSystem, mySrd);
fail();
} catch (UnprocessableEntityException e) {
assertEquals("Can not create multiple code systems with URI \"http://example.com/my_code_system\", already have one with resource ID: CodeSystem/" + id.getIdPart(), e.getMessage());
}
}
@Test
public void testCodeSystemWithDefinedCodes() {
//@formatter:off
@ -68,13 +171,358 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
.addConcept(new ConceptDefinitionComponent().setCode("BB").setDisplay("Code AB"));
//@formatter:on
IIdType id = myCodeSystemDao.create(codeSystem, new ServletRequestDetails()).getId().toUnqualified();
IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
Set<TermConcept> codes = myTermSvc.findCodesBelow(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "A");
assertThat(toCodes(codes), containsInAnyOrder("A", "AA", "AB"));
}
@Test
public void testExpandWithExcludeInExternalValueSet() {
createExternalCsAndLocalVs();
ValueSet vs = new ValueSet();
ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
ConceptSetComponent exclude = vs.getCompose().addExclude();
exclude.setSystem(URL_MY_CODE_SYSTEM);
exclude.addConcept().setCode("childAA");
exclude.addConcept().setCode("childAAA");
ValueSet result = myValueSetDao.expand(vs, null);
String encoded = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result);
ourLog.info(encoded);
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("ParentA", "ParentB", "childAB", "childAAB", "ParentC", "childBA", "childCA"));
}
@Test
public void testExpandWithInvalidExclude() {
createExternalCsAndLocalVs();
ValueSet vs = new ValueSet();
ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
/*
* No system set on exclude
*/
ConceptSetComponent exclude = vs.getCompose().addExclude();
exclude.addConcept().setCode("childAA");
exclude.addConcept().setCode("childAAA");
try {
myValueSetDao.expand(vs, null);
fail();
} catch (InvalidRequestException e) {
assertEquals("ValueSet contains exclude criteria with no system defined", e.getMessage());
}
}
@Test
public void testExpandWithNoResultsInLocalValueSet1() {
createLocalCsAndVs();
ValueSet vs = new ValueSet();
ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
include.addConcept().setCode("ZZZZ");
try {
myValueSetDao.expand(vs, null);
fail();
} catch (InvalidRequestException e) {
assertEquals("Unable to find code 'ZZZZ' in code system http://example.com/my_code_system", e.getMessage());
}
}
@Test
public void testExpandWithNoResultsInLocalValueSet2() {
createLocalCsAndVs();
ValueSet vs = new ValueSet();
ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM + "AA");
include.addConcept().setCode("A");
try {
myValueSetDao.expand(vs, null);
fail();
} catch (InvalidRequestException e) {
assertEquals("unable to find code system http://example.com/my_code_systemAA", e.getMessage());
}
}
@Test
public void testExpandWithSystemAndCodesAndFilterInExternalValueSet() {
createExternalCsAndLocalVs();
ValueSet vs = new ValueSet();
ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
include.addConcept().setCode("ParentA");
include.addConcept().setCode("childAA");
include.addConcept().setCode("childAAA");
include.addFilter().setProperty("display").setOp(FilterOperator.EQUAL).setValue("Parent B");
ValueSet result = myValueSetDao.expand(vs, null);
String encoded = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result);
ourLog.info(encoded);
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("ParentA", "childAA", "childAAA", "ParentB"));
int idx = codes.indexOf("childAA");
assertEquals("childAA", result.getExpansion().getContains().get(idx).getCode());
assertEquals("Child AA", result.getExpansion().getContains().get(idx).getDisplay());
assertEquals(URL_MY_CODE_SYSTEM, result.getExpansion().getContains().get(idx).getSystem());
}
@Test
public void testExpandWithDisplayInExternalValueSetFuzzyMatching() {
createExternalCsAndLocalVs();
ValueSet vs = new ValueSet();
ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
include.addFilter().setProperty("display").setOp(FilterOperator.EQUAL).setValue("parent a");
ValueSet result = myValueSetDao.expand(vs, null);
String encoded = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result);
ourLog.info(encoded);
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("ParentA"));
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
include.addFilter().setProperty("display").setOp(FilterOperator.EQUAL).setValue("pare");
result = myValueSetDao.expand(vs, null);
encoded = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result);
ourLog.info(encoded);
codes = toCodesContains(result.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("ParentA", "ParentB", "ParentC"));
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
include.addFilter().setProperty("display:exact").setOp(FilterOperator.EQUAL).setValue("pare");
result = myValueSetDao.expand(vs, null);
encoded = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result);
ourLog.info(encoded);
codes = toCodesContains(result.getExpansion().getContains());
assertThat(codes, empty());
}
@Test
public void testExpandWithSystemAndCodesAndFilterKeywordInLocalValueSet() {
createLocalCsAndVs();
ValueSet vs = new ValueSet();
ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
// include.addConcept().setCode("A");
// include.addConcept().setCode("AA");
// include.addConcept().setCode("AAA");
// include.addConcept().setCode("AB");
include.addFilter().setProperty("display").setOp(FilterOperator.EQUAL).setValue("AAA");
ValueSet result = myValueSetDao.expand(vs, null);
String encoded = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result);
ourLog.info(encoded);
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("AAA"));
assertEquals("AAA", result.getExpansion().getContains().get(0).getCode());
assertEquals("Code AAA", result.getExpansion().getContains().get(0).getDisplay());
assertEquals(URL_MY_CODE_SYSTEM, result.getExpansion().getContains().get(0).getSystem());
//
}
@Test
public void testExpandWithSystemAndCodesInLocalValueSet() {
createLocalCsAndVs();
ValueSet vs = new ValueSet();
ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
include.addConcept().setCode("A");
include.addConcept().setCode("AA");
include.addConcept().setCode("AAA");
include.addConcept().setCode("AB");
ValueSet result = myValueSetDao.expand(vs, null);
String encoded = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result);
ourLog.info(encoded);
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("A", "AA", "AAA", "AB"));
int idx = codes.indexOf("AAA");
assertEquals("AAA", result.getExpansion().getContains().get(idx).getCode());
assertEquals("Code AAA", result.getExpansion().getContains().get(idx).getDisplay());
assertEquals(URL_MY_CODE_SYSTEM, result.getExpansion().getContains().get(idx).getSystem());
// ValueSet expansion = myValueSetDao.expandByIdentifier(URL_MY_VALUE_SET, "cervical");
// ValueSet expansion = myValueSetDao.expandByIdentifier(URL_MY_VALUE_SET, "cervical");
//
}
@Test
public void testIndexingIsDeferredForLargeCodeSystems() {
myDaoConfig.setDeferIndexingForCodesystemsOfSize(1);
myTermSvc.setProcessDeferred(false);
createExternalCsAndLocalVs();
ValueSet vs = new ValueSet();
ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
include.addFilter().setProperty("concept").setOp(FilterOperator.ISA).setValue("ParentA");
ValueSet result = myValueSetDao.expand(vs, null);
String encoded = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result);
ourLog.info(encoded);
assertEquals(0, result.getExpansion().getContains().size());
myTermSvc.setProcessDeferred(true);
myTermSvc.saveDeferred();
myTermSvc.saveDeferred();
myTermSvc.saveDeferred();
myTermSvc.saveDeferred();
myTermSvc.saveDeferred();
myTermSvc.saveDeferred();
myTermSvc.saveDeferred();
vs = new ValueSet();
include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
include.addFilter().setProperty("concept").setOp(FilterOperator.ISA).setValue("ParentA");
result = myValueSetDao.expand(vs, null);
encoded = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result);
ourLog.info(encoded);
assertEquals(4, result.getExpansion().getContains().size());
assertThat(encoded, containsStringIgnoringCase("<code value=\"childAAB\"/>"));
}
/**
* Can't currently abort costly
*/
@Test
@Ignore
public void testRefuseCostlyExpansionFhirCodesystem() {
createLocalCsAndVs();
myDaoConfig.setMaximumExpansionSize(1);
SearchParameterMap params = new SearchParameterMap();
params.add(AuditEvent.SP_TYPE, new TokenParam(null, "http://hl7.org/fhir/ValueSet/audit-event-type").setModifier(TokenParamModifier.IN));
try {
myAuditEventDao.search(params);
fail();
} catch (InvalidRequestException e) {
assertEquals("", e.getMessage());
}
}
@Test
public void testRefuseCostlyExpansionLocalCodesystem() {
createLocalCsAndVs();
myDaoConfig.setMaximumExpansionSize(1);
SearchParameterMap params = new SearchParameterMap();
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "AAA").setModifier(TokenParamModifier.ABOVE));
try {
myObservationDao.search(params);
fail();
} catch (InvalidRequestException e) {
assertEquals("Expansion of ValueSet produced too many codes (maximum 1) - Operation aborted!", e.getMessage());
}
}
@Test
public void testSearchCodeAboveLocalCodesystem() {
createLocalCsAndVs();
Observation obsAA = new Observation();
obsAA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("AA");
IIdType idAA = myObservationDao.create(obsAA, mySrd).getId().toUnqualifiedVersionless();
Observation obsBA = new Observation();
obsBA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("BA");
IIdType idBA = myObservationDao.create(obsBA, mySrd).getId().toUnqualifiedVersionless();
Observation obsCA = new Observation();
obsCA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("CA");
IIdType idCA = myObservationDao.create(obsCA, mySrd).getId().toUnqualifiedVersionless();
SearchParameterMap params = new SearchParameterMap();
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "AAA").setModifier(TokenParamModifier.ABOVE));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), containsInAnyOrder(idAA.getValue()));
params = new SearchParameterMap();
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "A").setModifier(TokenParamModifier.ABOVE));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
}
@Test
public void testSearchCodeBelowAndAboveUnknownCodeSystem() {
SearchParameterMap params = new SearchParameterMap();
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "childAA").setModifier(TokenParamModifier.BELOW));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "childAA").setModifier(TokenParamModifier.ABOVE));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
}
@Test
public void testSearchCodeBelowLocalCodesystem() {
createLocalCsAndVs();
Observation obsAA = new Observation();
obsAA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("AA");
IIdType idAA = myObservationDao.create(obsAA, mySrd).getId().toUnqualifiedVersionless();
Observation obsBA = new Observation();
obsBA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("BA");
IIdType idBA = myObservationDao.create(obsBA, mySrd).getId().toUnqualifiedVersionless();
Observation obsCA = new Observation();
obsCA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("CA");
IIdType idCA = myObservationDao.create(obsCA, mySrd).getId().toUnqualifiedVersionless();
SearchParameterMap params = new SearchParameterMap();
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "A").setModifier(TokenParamModifier.BELOW));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), containsInAnyOrder(idAA.getValue()));
params = new SearchParameterMap();
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "AAA").setModifier(TokenParamModifier.BELOW));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
}
@Test
@Ignore
public void testSearchCodeInEmptyValueSet() {
@ -109,28 +557,6 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
}
@Test
public void testSearchCodeInLocalCodesystem() {
createLocalCsAndVs();
Observation obsAA = new Observation();
obsAA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("AA");
IIdType idAA = myObservationDao.create(obsAA, mySrd).getId().toUnqualifiedVersionless();
Observation obsBA = new Observation();
obsBA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("BA");
IIdType idBA = myObservationDao.create(obsBA, mySrd).getId().toUnqualifiedVersionless();
Observation obsCA = new Observation();
obsCA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("CA");
IIdType idCA = myObservationDao.create(obsCA, mySrd).getId().toUnqualifiedVersionless();
SearchParameterMap params = new SearchParameterMap();
params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), containsInAnyOrder(idAA.getValue(), idBA.getValue()));
}
@Test
public void testSearchCodeInExternalCodesystem() {
createExternalCsAndLocalVs();
@ -165,64 +591,6 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
}
private void createExternalCsAndLocalVs() {
CodeSystem codeSystem = createExternalCs();
createLocalVs(codeSystem);
}
private CodeSystem createExternalCs() {
CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
IIdType id = myCodeSystemDao.create(codeSystem, new ServletRequestDetails()).getId().toUnqualified();
ResourceTable table = myResourceTableDao.findOne(id.getIdPartAsLong());
TermCodeSystemVersion cs = new TermCodeSystemVersion();
cs.setResource(table);
cs.setResourceVersionId(table.getVersion());
TermConcept parentA = new TermConcept(cs, "ParentA").setDisplay("Parent A");
cs.getConcepts().add(parentA);
TermConcept childAA = new TermConcept(cs, "childAA").setDisplay("Child AA");
parentA.addChild(childAA, RelationshipTypeEnum.ISA);
TermConcept childAAA = new TermConcept(cs, "childAAA").setDisplay("Child AAA");
childAA.addChild(childAAA, RelationshipTypeEnum.ISA);
TermConcept childAAB = new TermConcept(cs, "childAAB").setDisplay("Child AAB");
childAA.addChild(childAAB, RelationshipTypeEnum.ISA);
TermConcept childAB = new TermConcept(cs, "childAB").setDisplay("Child AB");
parentA.addChild(childAB, RelationshipTypeEnum.ISA);
TermConcept parentB = new TermConcept(cs, "ParentB").setDisplay("Parent B");
cs.getConcepts().add(parentB);
myTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM, cs);
return codeSystem;
}
@Test
public void testSearchCodeBelowAndAboveUnknownCodeSystem() {
SearchParameterMap params = new SearchParameterMap();
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "childAA").setModifier(TokenParamModifier.BELOW));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "childAA").setModifier(TokenParamModifier.ABOVE));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
}
@Test
public void testSearchCodeInFhirCodesystem() {
createLocalCsAndVs();
@ -248,241 +616,28 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
assertThat(toUnqualifiedVersionlessIdValues(myAuditEventDao.search(params)), empty());
}
/**
* Can't currently abort costly
*/
@Test
@Ignore
public void testRefuseCostlyExpansionFhirCodesystem() {
public void testSearchCodeInLocalCodesystem() {
createLocalCsAndVs();
myDaoConfig.setMaximumExpansionSize(1);
Observation obsAA = new Observation();
obsAA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("AA");
IIdType idAA = myObservationDao.create(obsAA, mySrd).getId().toUnqualifiedVersionless();
Observation obsBA = new Observation();
obsBA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("BA");
IIdType idBA = myObservationDao.create(obsBA, mySrd).getId().toUnqualifiedVersionless();
Observation obsCA = new Observation();
obsCA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("CA");
IIdType idCA = myObservationDao.create(obsCA, mySrd).getId().toUnqualifiedVersionless();
SearchParameterMap params = new SearchParameterMap();
params.add(AuditEvent.SP_TYPE, new TokenParam(null, "http://hl7.org/fhir/ValueSet/audit-event-type").setModifier(TokenParamModifier.IN));
try {
myAuditEventDao.search(params);
fail();
} catch (InvalidRequestException e) {
assertEquals("", e.getMessage());
}
}
@Test
public void testRefuseCostlyExpansionLocalCodesystem() {
createLocalCsAndVs();
myDaoConfig.setMaximumExpansionSize(1);
SearchParameterMap params = new SearchParameterMap();
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "AAA").setModifier(TokenParamModifier.ABOVE));
try {
myObservationDao.search(params);
fail();
} catch (InvalidRequestException e) {
assertEquals("Expansion of ValueSet produced too many codes (maximum 1) - Operation aborted!", e.getMessage());
}
}
@Test
public void testExpandWithSystemAndCodesInLocalValueSet() {
createLocalCsAndVs();
ValueSet vs = new ValueSet();
ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
include.addConcept().setCode("A");
include.addConcept().setCode("AA");
include.addConcept().setCode("AAA");
include.addConcept().setCode("AB");
ValueSet result = myValueSetDao.expand(vs, null);
String encoded = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result);
ourLog.info(encoded);
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("A", "AA", "AAA", "AB"));
int idx = codes.indexOf("AAA");
assertEquals("AAA", result.getExpansion().getContains().get(idx).getCode());
assertEquals("Code AAA", result.getExpansion().getContains().get(idx).getDisplay());
assertEquals(URL_MY_CODE_SYSTEM, result.getExpansion().getContains().get(idx).getSystem());
// ValueSet expansion = myValueSetDao.expandByIdentifier(URL_MY_VALUE_SET, "cervical");
// ValueSet expansion = myValueSetDao.expandByIdentifier(URL_MY_VALUE_SET, "cervical");
//
}
@Test
public void testExpandWithSystemAndCodesAndFilterInExternalValueSet() {
createExternalCsAndLocalVs();
ValueSet vs = new ValueSet();
ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
include.addConcept().setCode("ParentA");
include.addConcept().setCode("childAA");
include.addConcept().setCode("childAAA");
include.addFilter().setProperty("display").setOp(FilterOperator.EQUAL).setValue("Parent B");
ValueSet result = myValueSetDao.expand(vs, null);
String encoded = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result);
ourLog.info(encoded);
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("ParentA", "childAA", "childAAA", "ParentB"));
int idx = codes.indexOf("childAA");
assertEquals("childAA", result.getExpansion().getContains().get(idx).getCode());
assertEquals("Child AA", result.getExpansion().getContains().get(idx).getDisplay());
assertEquals(URL_MY_CODE_SYSTEM, result.getExpansion().getContains().get(idx).getSystem());
}
@Test
public void testIndexingIsDeferredForLargeCodeSystems() {
myDaoConfig.setDeferIndexingForCodesystemsOfSize(1);
myTermSvc.setProcessDeferred(false);
createExternalCsAndLocalVs();
ValueSet vs = new ValueSet();
ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
include.addFilter().setProperty("display").setOp(FilterOperator.ISA).setValue("ParentA");
ValueSet result = myValueSetDao.expand(vs, null);
String encoded = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result);
ourLog.info(encoded);
assertEquals(0, result.getExpansion().getContains().size());
myTermSvc.setProcessDeferred(true);
myTermSvc.saveDeferred();
myTermSvc.saveDeferred();
myTermSvc.saveDeferred();
myTermSvc.saveDeferred();
myTermSvc.saveDeferred();
myTermSvc.saveDeferred();
myTermSvc.saveDeferred();
result = myValueSetDao.expand(vs, null);
encoded = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result);
ourLog.info(encoded);
assertEquals(4, result.getExpansion().getContains().size());
params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), containsInAnyOrder(idAA.getValue(), idBA.getValue()));
}
@Test
public void testExpandWithExcludeInExternalValueSet() {
createExternalCsAndLocalVs();
ValueSet vs = new ValueSet();
ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
ConceptSetComponent exclude = vs.getCompose().addExclude();
exclude.setSystem(URL_MY_CODE_SYSTEM);
exclude.addConcept().setCode("childAA");
exclude.addConcept().setCode("childAAA");
ValueSet result = myValueSetDao.expand(vs, null);
String encoded = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result);
ourLog.info(encoded);
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("ParentA", "ParentB", "childAB", "childAAB"));
}
@Test
public void testExpandWithInvalidExclude() {
createExternalCsAndLocalVs();
ValueSet vs = new ValueSet();
ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
/*
* No system set on exclude
*/
ConceptSetComponent exclude = vs.getCompose().addExclude();
exclude.addConcept().setCode("childAA");
exclude.addConcept().setCode("childAAA");
try {
myValueSetDao.expand(vs, null);
fail();
} catch (InvalidRequestException e) {
assertEquals("ValueSet contains exclude criteria with no system defined", e.getMessage());
}
}
@Test
public void testExpandWithSystemAndCodesAndFilterKeywordInLocalValueSet() {
createLocalCsAndVs();
ValueSet vs = new ValueSet();
ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
// include.addConcept().setCode("A");
// include.addConcept().setCode("AA");
// include.addConcept().setCode("AAA");
// include.addConcept().setCode("AB");
include.addFilter().setProperty("display").setOp(FilterOperator.EQUAL).setValue("AAA");
ValueSet result = myValueSetDao.expand(vs, null);
String encoded = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result);
ourLog.info(encoded);
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("AAA"));
assertEquals("AAA", result.getExpansion().getContains().get(0).getCode());
assertEquals("Code AAA", result.getExpansion().getContains().get(0).getDisplay());
assertEquals(URL_MY_CODE_SYSTEM, result.getExpansion().getContains().get(0).getSystem());
//
}
@Test
public void testExpandWithNoResultsInLocalValueSet1() {
createLocalCsAndVs();
ValueSet vs = new ValueSet();
ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
include.addConcept().setCode("ZZZZ");
try {
myValueSetDao.expand(vs, null);
fail();
} catch (InvalidRequestException e) {
assertEquals("Unable to find code 'ZZZZ' in code system http://example.com/my_code_system", e.getMessage());
}
}
@Test
public void testExpandWithNoResultsInLocalValueSet2() {
createLocalCsAndVs();
ValueSet vs = new ValueSet();
ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM + "AA");
include.addConcept().setCode("A");
try {
myValueSetDao.expand(vs, null);
fail();
} catch (InvalidRequestException e) {
assertEquals("unable to find code system http://example.com/my_code_systemAA", e.getMessage());
}
}
private ArrayList<String> toCodesContains(List<ValueSetExpansionContainsComponent> theContains) {
ArrayList<String> retVal = new ArrayList<String>();
@ -493,114 +648,9 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
}
@Test
public void testSearchCodeAboveLocalCodesystem() {
createLocalCsAndVs();
Observation obsAA = new Observation();
obsAA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("AA");
IIdType idAA = myObservationDao.create(obsAA, mySrd).getId().toUnqualifiedVersionless();
Observation obsBA = new Observation();
obsBA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("BA");
IIdType idBA = myObservationDao.create(obsBA, mySrd).getId().toUnqualifiedVersionless();
Observation obsCA = new Observation();
obsCA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("CA");
IIdType idCA = myObservationDao.create(obsCA, mySrd).getId().toUnqualifiedVersionless();
SearchParameterMap params = new SearchParameterMap();
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "AAA").setModifier(TokenParamModifier.ABOVE));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), containsInAnyOrder(idAA.getValue()));
params = new SearchParameterMap();
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "A").setModifier(TokenParamModifier.ABOVE));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
}
@Before
public void before() {
myDaoConfig.setMaximumExpansionSize(5000);
}
@After
public void after() {
myDaoConfig.setDeferIndexingForCodesystemsOfSize(new DaoConfig().getDeferIndexingForCodesystemsOfSize());
}
@Test
public void testSearchCodeBelowLocalCodesystem() {
createLocalCsAndVs();
Observation obsAA = new Observation();
obsAA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("AA");
IIdType idAA = myObservationDao.create(obsAA, mySrd).getId().toUnqualifiedVersionless();
Observation obsBA = new Observation();
obsBA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("BA");
IIdType idBA = myObservationDao.create(obsBA, mySrd).getId().toUnqualifiedVersionless();
Observation obsCA = new Observation();
obsCA.getCode().addCoding().setSystem(URL_MY_CODE_SYSTEM).setCode("CA");
IIdType idCA = myObservationDao.create(obsCA, mySrd).getId().toUnqualifiedVersionless();
SearchParameterMap params = new SearchParameterMap();
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "A").setModifier(TokenParamModifier.BELOW));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), containsInAnyOrder(idAA.getValue()));
params = new SearchParameterMap();
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "AAA").setModifier(TokenParamModifier.BELOW));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(params)), empty());
}
private void createLocalCsAndVs() {
//@formatter:off
CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
codeSystem.setContent(CodeSystemContentMode.COMPLETE);
codeSystem
.addConcept().setCode("A").setDisplay("Code A")
.addConcept(new ConceptDefinitionComponent().setCode("AA").setDisplay("Code AA")
.addConcept(new ConceptDefinitionComponent().setCode("AAA").setDisplay("Code AAA"))
)
.addConcept(new ConceptDefinitionComponent().setCode("AB").setDisplay("Code AB"));
codeSystem
.addConcept().setCode("B").setDisplay("Code B")
.addConcept(new ConceptDefinitionComponent().setCode("BA").setDisplay("Code BA"))
.addConcept(new ConceptDefinitionComponent().setCode("BB").setDisplay("Code BB"));
//@formatter:on
myCodeSystemDao.create(codeSystem, new ServletRequestDetails());
createLocalVs(codeSystem);
}
private void createLocalVs(CodeSystem codeSystem) {
ValueSet valueSet = new ValueSet();
valueSet.setUrl(URL_MY_VALUE_SET);
valueSet.getCompose().addInclude().setSystem(codeSystem.getUrl());
myValueSetDao.create(valueSet, mySrd);
}
@Test
public void testCodeSystemCreateDuplicateFails() {
CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
codeSystem.setContent(CodeSystemContentMode.COMPLETE);
IIdType id = myCodeSystemDao.create(codeSystem, new ServletRequestDetails()).getId().toUnqualified();
codeSystem = new CodeSystem();
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
codeSystem.setContent(CodeSystemContentMode.COMPLETE);
try {
myCodeSystemDao.create(codeSystem, new ServletRequestDetails());
fail();
} catch (UnprocessableEntityException e) {
assertEquals("Can not create multiple code systems with URI \"http://example.com/my_code_system\", already have one with resource ID: CodeSystem/" + id.getIdPart(), e.getMessage());
}
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
}

View File

@ -1493,6 +1493,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
for (int i = 0; i < 10; i++) {
Thread.sleep(100);
preDates.add(new Date());
Thread.sleep(100);
patient.setId(id);
patient.getName().get(0).getFamily().get(0).setValue(methodName + "_i");
ids.add(myPatientDao.update(patient, mySrd).getId().toUnqualified().getValue());

View File

@ -26,7 +26,6 @@ import org.junit.Test;
import org.springframework.transaction.annotation.Transactional;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.TestUtil;
public class FhirResourceDaoDstu3ValueSetTest extends BaseJpaDstu3Test {
@ -62,7 +61,7 @@ public class FhirResourceDaoDstu3ValueSetTest extends BaseJpaDstu3Test {
StringType display = null;
Coding coding = null;
CodeableConcept codeableConcept = null;
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
assertFalse(result.isResult());
}
@ -75,7 +74,7 @@ public class FhirResourceDaoDstu3ValueSetTest extends BaseJpaDstu3Test {
StringType display = null;
Coding coding = null;
CodeableConcept codeableConcept = null;
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
assertTrue(result.isResult());
assertEquals("Systolic blood pressure--expiration", result.getDisplay());
}
@ -89,7 +88,7 @@ public class FhirResourceDaoDstu3ValueSetTest extends BaseJpaDstu3Test {
StringType display = null;
Coding coding = null;
CodeableConcept codeableConcept = null;
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
assertTrue(result.isResult());
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
}
@ -103,7 +102,7 @@ public class FhirResourceDaoDstu3ValueSetTest extends BaseJpaDstu3Test {
StringType display = new StringType("Systolic blood pressure at First encounterXXXX");
Coding coding = null;
CodeableConcept codeableConcept = null;
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
assertFalse(result.isResult());
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
}
@ -117,7 +116,7 @@ public class FhirResourceDaoDstu3ValueSetTest extends BaseJpaDstu3Test {
StringType display = new StringType("Systolic blood pressure at First encounter");
Coding coding = null;
CodeableConcept codeableConcept = null;
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
assertTrue(result.isResult());
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
}
@ -132,7 +131,7 @@ public class FhirResourceDaoDstu3ValueSetTest extends BaseJpaDstu3Test {
Coding coding = null;
CodeableConcept codeableConcept = new CodeableConcept();
codeableConcept.addCoding().setSystem("http://acme.org").setCode("11378-7");
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
assertTrue(result.isResult());
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
}
@ -146,7 +145,7 @@ public class FhirResourceDaoDstu3ValueSetTest extends BaseJpaDstu3Test {
StringType display = null;
Coding coding = null;
CodeableConcept codeableConcept = null;
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
assertTrue(result.isResult());
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
}
@ -155,7 +154,7 @@ public class FhirResourceDaoDstu3ValueSetTest extends BaseJpaDstu3Test {
public void testExpandById() throws IOException {
String resp;
ValueSet expanded = myValueSetDao.expand(myExtensionalVsId, null);
ValueSet expanded = myValueSetDao.expand(myExtensionalVsId, null, mySrd);
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
assertThat(resp, containsString("<ValueSet xmlns=\"http://hl7.org/fhir\">"));
@ -176,7 +175,7 @@ public class FhirResourceDaoDstu3ValueSetTest extends BaseJpaDstu3Test {
* Filter with display name
*/
expanded = myValueSetDao.expand(myExtensionalVsId, ("systolic"));
expanded = myValueSetDao.expand(myExtensionalVsId, ("systolic"), mySrd);
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
//@formatter:off

View File

@ -191,7 +191,7 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
});
assertEquals(null, entity.getIndexStatus());
mySystemDao.performReindexingPass(null, mySrd);
mySystemDao.performReindexingPass(null);
entity = new TransactionTemplate(myTxManager).execute(new TransactionCallback<ResourceTable>() {
@Override
@ -202,7 +202,7 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
assertEquals(Long.valueOf(1), entity.getIndexStatus());
// Just make sure this doesn't cause a choke
mySystemDao.performReindexingPass(100000, mySrd);
mySystemDao.performReindexingPass(100000);
// Try making the resource unparseable
@ -224,7 +224,7 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
}
});
mySystemDao.performReindexingPass(null, mySrd);
mySystemDao.performReindexingPass(null);
entity = new TransactionTemplate(myTxManager).execute(new TransactionCallback<ResourceTable>() {
@Override

View File

@ -24,7 +24,6 @@ import ca.uhn.fhir.model.primitive.CodeDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.TestUtil;
public class ResourceProviderDstu2ValueSetTest extends BaseResourceProviderDstu2Test {
@ -251,7 +250,7 @@ public class ResourceProviderDstu2ValueSetTest extends BaseResourceProviderDstu2
expanded = (ValueSet) respParam.getParameter().get(0).getResource();
//@formatter:on
expanded = myValueSetDao.expand(myExtensionalVsId, ("systolic"));
expanded = myValueSetDao.expand(myExtensionalVsId, ("systolic"), mySrd);
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
//@formatter:off

View File

@ -32,7 +32,6 @@ import ca.uhn.fhir.model.dstu2.valueset.SubscriptionStatusEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.TestUtil;
public class SubscriptionsDstu2Test extends BaseResourceProviderDstu2Test {

View File

@ -1,9 +1,12 @@
package ca.uhn.fhir.jpa.provider.dstu3;
import static ca.uhn.fhir.jpa.dao.dstu3.FhirResourceDaoDstu3TerminologyTest.*;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.containsStringIgnoringCase;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.stringContainsInOrder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
@ -16,6 +19,10 @@ import org.hl7.fhir.dstu3.model.Parameters;
import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.dstu3.model.UriType;
import org.hl7.fhir.dstu3.model.ValueSet;
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.dstu3.model.ValueSet.FilterOperator;
import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.AfterClass;
import org.junit.Before;
@ -23,6 +30,10 @@ import org.junit.Ignore;
import org.junit.Test;
import org.springframework.transaction.annotation.Transactional;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.TestUtil;
@ -30,6 +41,8 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderDstu3ValueSetTest.class);
private IIdType myExtensionalVsId;
private IIdType myLocalValueSetId;
private ValueSet myLocalVs;
@AfterClass
public static void afterClassClearContext() {
@ -77,6 +90,140 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
}
@Test
public void testExpandLocalVsAgainstExternalCs() throws IOException {
createExternalCsAndLocalVs();
assertNotNull(myLocalValueSetId);
//@formatter:off
Parameters respParam = ourClient
.operation()
.onInstance(myLocalValueSetId)
.named("expand")
.withNoParameters(Parameters.class)
.execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
//@formatter:on
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
assertThat(resp, containsStringIgnoringCase("<code value=\"childAAA\"/>"));
assertThat(resp, containsStringIgnoringCase("<code value=\"childAAB\"/>"));
assertThat(resp, not(containsStringIgnoringCase("<code value=\"ParentA\"/>")));
}
@Test
public void testExpandLocalVsWithUnknownCode() throws IOException {
createExternalCsAndLocalVsWithUnknownCode();
assertNotNull(myLocalValueSetId);
//@formatter:off
try {
ourClient
.operation()
.onInstance(myLocalValueSetId)
.named("expand")
.withNoParameters(Parameters.class)
.execute();
} catch (InvalidRequestException e) {
assertEquals("HTTP 400 Bad Request: Invalid filter criteria - code does not exist: {http://example.com/my_code_system}childFOOOOOOO", e.getMessage());
}
//@formatter:on
}
@Test
public void testExpandInlineVsAgainstBuiltInCs() throws IOException {
createLocalVsPointingAtBuiltInCodeSystem();
assertNotNull(myLocalValueSetId);
//@formatter:off
Parameters respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("expand")
.withParameter(Parameters.class, "valueSet", myLocalVs)
.execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
//@formatter:on
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
assertThat(resp, containsStringIgnoringCase("<code value=\"M\"/>"));
}
@Test
public void testExpandLocalVsAgainstBuiltInCs() throws IOException {
createLocalVsPointingAtBuiltInCodeSystem();
assertNotNull(myLocalValueSetId);
//@formatter:off
Parameters respParam = ourClient
.operation()
.onInstance(myLocalValueSetId)
.named("expand")
.withNoParameters(Parameters.class)
.execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
//@formatter:on
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
assertThat(resp, containsStringIgnoringCase("<code value=\"M\"/>"));
}
@Test
public void testExpandLocalVsCanonicalAgainstExternalCs() throws IOException {
createExternalCsAndLocalVs();
assertNotNull(myLocalValueSetId);
//@formatter:off
Parameters respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("expand")
.withParameter(Parameters.class, "identifier", new UriType(URL_MY_VALUE_SET))
.execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
//@formatter:on
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
assertThat(resp, containsStringIgnoringCase("<code value=\"childAAA\"/>"));
assertThat(resp, containsStringIgnoringCase("<code value=\"childAAB\"/>"));
assertThat(resp, not(containsStringIgnoringCase("<code value=\"ParentA\"/>")));
}
@Test
public void testExpandInlineVsAgainstExternalCs() throws IOException {
createExternalCsAndLocalVs();
assertNotNull(myLocalVs);
myLocalVs.setId("");
//@formatter:off
Parameters respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("expand")
.withParameter(Parameters.class, "valueSet", myLocalVs)
.execute();
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
//@formatter:on
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
assertThat(resp, containsStringIgnoringCase("<code value=\"childAAA\"/>"));
assertThat(resp, containsStringIgnoringCase("<code value=\"childAAB\"/>"));
assertThat(resp, not(containsStringIgnoringCase("<code value=\"ParentA\"/>")));
}
@Test
public void testExpandByIdWithFilter() throws IOException {
@ -259,4 +406,102 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
assertEquals(true, ((BooleanType)respParam.getParameter().get(0).getValue()).booleanValue());
}
private CodeSystem createExternalCs() {
CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
ResourceTable table = myResourceTableDao.findOne(id.getIdPartAsLong());
TermCodeSystemVersion cs = new TermCodeSystemVersion();
cs.setResource(table);
cs.setResourceVersionId(table.getVersion());
TermConcept parentA = new TermConcept(cs, "ParentA").setDisplay("Parent A");
cs.getConcepts().add(parentA);
TermConcept childAA = new TermConcept(cs, "childAA").setDisplay("Child AA");
parentA.addChild(childAA, RelationshipTypeEnum.ISA);
TermConcept childAAA = new TermConcept(cs, "childAAA").setDisplay("Child AAA");
childAA.addChild(childAAA, RelationshipTypeEnum.ISA);
TermConcept childAAB = new TermConcept(cs, "childAAB").setDisplay("Child AAB");
childAA.addChild(childAAB, RelationshipTypeEnum.ISA);
TermConcept childAB = new TermConcept(cs, "childAB").setDisplay("Child AB");
parentA.addChild(childAB, RelationshipTypeEnum.ISA);
TermConcept parentB = new TermConcept(cs, "ParentB").setDisplay("Parent B");
cs.getConcepts().add(parentB);
myTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM, cs);
return codeSystem;
}
private void createExternalCsAndLocalVs() {
CodeSystem codeSystem = createExternalCs();
createLocalVs(codeSystem);
}
private void createExternalCsAndLocalVsWithUnknownCode() {
CodeSystem codeSystem = createExternalCs();
createLocalVsWithUnknownCode(codeSystem);
}
private void createLocalCsAndVs() {
//@formatter:off
CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
codeSystem.setContent(CodeSystemContentMode.COMPLETE);
codeSystem
.addConcept().setCode("A").setDisplay("Code A")
.addConcept(new ConceptDefinitionComponent().setCode("AA").setDisplay("Code AA")
.addConcept(new ConceptDefinitionComponent().setCode("AAA").setDisplay("Code AAA"))
)
.addConcept(new ConceptDefinitionComponent().setCode("AB").setDisplay("Code AB"));
codeSystem
.addConcept().setCode("B").setDisplay("Code B")
.addConcept(new ConceptDefinitionComponent().setCode("BA").setDisplay("Code BA"))
.addConcept(new ConceptDefinitionComponent().setCode("BB").setDisplay("Code BB"));
//@formatter:on
myCodeSystemDao.create(codeSystem, mySrd);
createLocalVs(codeSystem);
}
private void createLocalVs(CodeSystem codeSystem) {
myLocalVs = new ValueSet();
myLocalVs.setUrl(URL_MY_VALUE_SET);
ConceptSetComponent include = myLocalVs.getCompose().addInclude();
include.setSystem(codeSystem.getUrl());
include.addFilter().setProperty("concept").setOp(FilterOperator.ISA).setValue("childAA");
myLocalValueSetId = myValueSetDao.create(myLocalVs, mySrd).getId().toUnqualifiedVersionless();
}
private void createLocalVsWithUnknownCode(CodeSystem codeSystem) {
myLocalVs = new ValueSet();
myLocalVs.setUrl(URL_MY_VALUE_SET);
ConceptSetComponent include = myLocalVs.getCompose().addInclude();
include.setSystem(codeSystem.getUrl());
include.addFilter().setProperty("concept").setOp(FilterOperator.ISA).setValue("childFOOOOOOO");
myLocalValueSetId = myValueSetDao.create(myLocalVs, mySrd).getId().toUnqualifiedVersionless();
}
private void createLocalVsPointingAtBuiltInCodeSystem() {
myLocalVs = new ValueSet();
myLocalVs.setUrl(URL_MY_VALUE_SET);
ConceptSetComponent include = myLocalVs.getCompose().addInclude();
include.setSystem("http://hl7.org/fhir/v3/MaritalStatus");
myLocalValueSetId = myValueSetDao.create(myLocalVs, mySrd).getId().toUnqualifiedVersionless();
}
}

View File

@ -367,6 +367,19 @@ public class SystemProviderDstu3Test extends BaseJpaDstu3Test {
}
}
@Test
public void testMarkResourcesForReindexing() throws Exception {
HttpGet get = new HttpGet(ourServerBase + "/$mark-all-resources-for-reindexing");
CloseableHttpResponse http = ourHttpClient.execute(get);
try {
String output = IOUtils.toString(http.getEntity().getContent());
ourLog.info(output);
assertEquals(200, http.getStatusLine().getStatusCode());
} finally {
IOUtils.closeQuietly(http);;
}
}
@Transactional(propagation = Propagation.NEVER)
@Test
public void testSuggestKeywords() throws Exception {

View File

@ -30,10 +30,6 @@ public class TerminologyLoaderSvcIntegrationTest extends BaseJpaDstu3Test {
@Test
@Ignore
public void testLoadAndStoreSnomedCt() {
Map<String, File> files = new HashMap<String, File>();
files.put(TerminologyLoaderSvc.SCT_FILE_CONCEPT, new File("/Users/james/tmp/sct/SnomedCT_Release_INT_20160131_Full/Terminology/sct2_Concept_Full_INT_20160131.txt"));
files.put(TerminologyLoaderSvc.SCT_FILE_DESCRIPTION, new File("/Users/james/tmp/sct/SnomedCT_Release_INT_20160131_Full/Terminology/sct2_Description_Full-en_INT_20160131.txt"));
files.put(TerminologyLoaderSvc.SCT_FILE_RELATIONSHIP, new File("/Users/james/tmp/sct/SnomedCT_Release_INT_20160131_Full/Terminology/sct2_Relationship_Full_INT_20160131.txt"));
// myLoader.processSnomedCtFiles(files, mySrd);
}

View File

@ -1,17 +1,17 @@
package ca.uhn.fhir.jpa.term;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInRelativeOrder;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
@ -25,6 +25,7 @@ import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.Validate;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@ -79,6 +80,21 @@ public class TerminologyLoaderSvcTest {
mySvc.loadLoinc(list(bos1.toByteArray(), bos2.toByteArray()), details);
}
/**
* This is just for trying stuff, it won't run without
* local files external to the git repo
*/
@Ignore
@Test
public void testLoadSnomedCtAgainstRealFile() throws Exception {
byte[] bytes = IOUtils.toByteArray(new FileInputStream("/Users/james/Downloads/SnomedCT_Release_INT_20160131_Full.zip"));
RequestDetails details = mock(RequestDetails.class);
mySvc.loadSnomedCt(list(bytes), details);
}
@Test
public void testLoadSnomedCt() throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();

View File

@ -42,7 +42,7 @@ public class TerminologySvcImplTest extends BaseJpaDstu3Test {
CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(CS_URL);
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
IIdType id = myCodeSystemDao.create(codeSystem, new ServletRequestDetails()).getId().toUnqualified();
IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
ResourceTable table = myResourceTableDao.findOne(id.getIdPartAsLong());
@ -109,14 +109,14 @@ public class TerminologySvcImplTest extends BaseJpaDstu3Test {
assertThat(mySystemDao.markAllResourcesForReindexing(), greaterThan(0));
assertThat(mySystemDao.performReindexingPass(100, mySrd), greaterThan(0));
assertThat(mySystemDao.performReindexingPass(100), greaterThan(0));
}
private IIdType createCodeSystem() {
CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(CS_URL);
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
IIdType id = myCodeSystemDao.create(codeSystem, new ServletRequestDetails()).getId().toUnqualified();
IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
ResourceTable table = myResourceTableDao.findOne(id.getIdPartAsLong());
@ -173,7 +173,7 @@ public class TerminologySvcImplTest extends BaseJpaDstu3Test {
CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(CS_URL);
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
IIdType id = myCodeSystemDao.create(codeSystem, new ServletRequestDetails()).getId().toUnqualified();
IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
ResourceTable table = myResourceTableDao.findOne(id.getIdPartAsLong());
@ -187,7 +187,7 @@ public class TerminologySvcImplTest extends BaseJpaDstu3Test {
cs = new TermCodeSystemVersion();
TermConcept parentA = new TermConcept(cs, "ParentA");
cs.getConcepts().add(parentA);
id = myCodeSystemDao.update(codeSystem, new ServletRequestDetails()).getId().toUnqualified();
id = myCodeSystemDao.update(codeSystem, mySrd).getId().toUnqualified();
table = myResourceTableDao.findOne(id.getIdPartAsLong());
cs.setResource(table);
cs.setResourceVersionId(table.getVersion());
@ -197,7 +197,7 @@ public class TerminologySvcImplTest extends BaseJpaDstu3Test {
codeSystem = new CodeSystem();
codeSystem.setUrl(CS_URL);
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
id = myCodeSystemDao.create(codeSystem, new ServletRequestDetails()).getId().toUnqualified();
id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
table = myResourceTableDao.findOne(id.getIdPartAsLong());
cs.setResource(table);
cs.setResourceVersionId(table.getVersion());

View File

@ -17,3 +17,4 @@ id effectiveTime active moduleId definitionStatusId
207527008 20020131 1 900000000000207008 900000000000074008
207527008 20040731 1 900000000000207008 900000000000073002
207527008 20090731 0 900000000000207008 900000000000074008
404684003 20040131 1 900000000000207008 900000000000074008

View File

@ -10,7 +10,6 @@ import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Import;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.orm.jpa.JpaTransactionManager;
@ -19,6 +18,8 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu1;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhirtest.interceptor.PublicSecurityInterceptor;
@Configuration
@Import(CommonConfig.class)
@ -38,6 +39,11 @@ public class TestDstu1Config extends BaseJavaConfigDstu1 {
return new PropertySourcesPlaceholderConfigurer();
}
@Bean
public IServerInterceptor securityInterceptor() {
return new PublicSecurityInterceptor();
}
@Bean()
public DaoConfig daoConfig() {
DaoConfig retVal = new DaoConfig();

View File

@ -23,6 +23,7 @@ import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu2;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu2;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhirtest.interceptor.PublicSecurityInterceptor;
@Configuration
@Import(CommonConfig.class)
@ -46,6 +47,11 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
return new PropertySourcesPlaceholderConfigurer();
}
@Bean
public IServerInterceptor securityInterceptor() {
return new PublicSecurityInterceptor();
}
@Bean()
public DaoConfig daoConfig() {
DaoConfig retVal = new DaoConfig();

View File

@ -28,6 +28,7 @@ import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
import ca.uhn.fhir.rest.server.interceptor.ResponseValidatingInterceptor;
import ca.uhn.fhir.validation.ResultSeverityEnum;
import ca.uhn.fhirtest.interceptor.PublicSecurityInterceptor;
@Configuration
@Import(CommonConfig.class)
@ -57,6 +58,11 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
return retVal;
}
@Bean
public IServerInterceptor securityInterceptor() {
return new PublicSecurityInterceptor();
}
@Bean(name = "myPersistenceDataSourceDstu3", destroyMethod = "close")
@DependsOn("dbServer")
public DataSource dataSource() {

View File

@ -0,0 +1,61 @@
package ca.uhn.fhirtest.interceptor;
import static org.apache.commons.lang3.StringUtils.isBlank;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import ca.uhn.fhir.jpa.provider.BaseJpaSystemProvider;
import ca.uhn.fhir.jpa.provider.dstu3.TerminologyUploaderProviderDstu3;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor;
import ca.uhn.fhir.rest.server.interceptor.auth.IAuthRule;
import ca.uhn.fhir.rest.server.interceptor.auth.RuleBuilder;
public class PublicSecurityInterceptor extends AuthorizationInterceptor {
private HashSet<String> myTokens;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(PublicSecurityInterceptor.class);
public PublicSecurityInterceptor() {
String passwordsString = System.getProperty("fhir.tdlpass");
String[] passwords = passwordsString.split(",");
myTokens = new HashSet<String>(Arrays.asList(passwords));
ourLog.info("We have {} valid security tokens", myTokens.size());
}
@Override
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
String authHeader = theRequestDetails.getHeader("Authorization");
//@formatter:off
if (isBlank(authHeader)) {
return new RuleBuilder()
.deny().operation().named(BaseJpaSystemProvider.MARK_ALL_RESOURCES_FOR_REINDEXING).onServer().andThen()
.deny().operation().named(TerminologyUploaderProviderDstu3.UPLOAD_EXTERNAL_CODE_SYSTEM).onServer().andThen()
.allowAll()
.build();
}
//@formatter:off
if (!authHeader.startsWith("Bearer ")) {
throw new ForbiddenOperationException("Invalid bearer token, must be in the form \"Authorization: Bearer [token]\"");
}
String token = authHeader.substring("Bearer ".length()).trim();
if (!myTokens.contains(token)) {
ourLog.error("Invalid token '{}' - Valid are: {}", token, myTokens);
throw new ForbiddenOperationException("Unknown/expired bearer token");
}
ourLog.info("User logged in with bearer token: " + token.substring(0, 4) + "...");
return new RuleBuilder()
.allowAll()
.build();
}
}

View File

@ -1,17 +1,35 @@
package ca.uhn.fhir.rest.param;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import java.util.Date;
import java.util.TimeZone;
import org.junit.Test;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.InstantDt;
public class DateParamTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(DateParamTest.class);
@SuppressWarnings("deprecation")
@Test
public void testConstructors() {
new DateParam();
new DateParam("2011-01-02");
new DateParam(ParamPrefixEnum.GREATERTHAN,new Date());
new DateParam(ParamPrefixEnum.GREATERTHAN,new DateTimeDt("2011-01-02"));
new DateParam(ParamPrefixEnum.GREATERTHAN,InstantDt.withCurrentTime());
new DateParam(ParamPrefixEnum.GREATERTHAN,"2011-01-02");
new DateParam(QuantityCompararatorEnum.GREATERTHAN,new Date());
new DateParam(QuantityCompararatorEnum.GREATERTHAN,new DateTimeDt("2011-01-02"));
new DateParam(QuantityCompararatorEnum.GREATERTHAN,InstantDt.withCurrentTime());
new DateParam(QuantityCompararatorEnum.GREATERTHAN,"2011-01-02");
}
@Test
public void testParse() {
Date date = new Date();

View File

@ -1,5 +1,6 @@
package ca.uhn.fhir.rest.server.interceptor.auth;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@ -32,7 +33,6 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
@ -40,11 +40,13 @@ import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.Observation;
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
import ca.uhn.fhir.model.dstu2.resource.Parameters;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.valueset.BundleTypeEnum;
import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.Delete;
import ca.uhn.fhir.rest.annotation.IdParam;
@ -55,14 +57,19 @@ import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.annotation.Transaction;
import ca.uhn.fhir.rest.annotation.TransactionParam;
import ca.uhn.fhir.rest.annotation.Update;
import ca.uhn.fhir.rest.annotation.Validate;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.ValidationModeEnum;
import ca.uhn.fhir.rest.method.IRequestOperationCallback;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.AddProfileTagEnum;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import ca.uhn.fhir.util.PortUtil;
import ca.uhn.fhir.util.TestUtil;
@ -158,6 +165,14 @@ public class AuthorizationInterceptorDstu2Test {
assertThat(response, containsString("Access denied by rule: Rule 1"));
assertEquals(403, status.getStatusLine().getStatusCode());
assertTrue(ourHitMethod);
ourHitMethod = false;
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$validate");
status = ourClient.execute(httpGet);
extractResponseAndClose(status);
assertEquals(200, status.getStatusLine().getStatusCode());
assertTrue(ourHitMethod);
}
@Test
@ -404,6 +419,15 @@ public class AuthorizationInterceptorDstu2Test {
assertThat(response, containsString("Access denied by rule: Default Rule"));
assertEquals(403, status.getStatusLine().getStatusCode());
assertTrue(ourHitMethod);
ourHitMethod = false;
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$validate");
status = ourClient.execute(httpGet);
response = extractResponseAndClose(status);
ourLog.info(response);
assertThat(response, containsString("Access denied by rule: Default Rule"));
assertEquals(403, status.getStatusLine().getStatusCode());
assertFalse(ourHitMethod);
}
@Test
@ -770,6 +794,7 @@ public class AuthorizationInterceptorDstu2Test {
//@formatter:off
return new RuleBuilder()
.allow("Rule 1").write().resourcesOfType(Patient.class).inCompartment("Patient", new IdDt("Patient/1")).andThen()
.allow("Rule 1b").write().resourcesOfType(Patient.class).inCompartment("Patient", new IdDt("Patient/1123")).andThen()
.allow("Rule 2").write().resourcesOfType(Observation.class).inCompartment("Patient", new IdDt("Patient/1"))
.build();
//@formatter:on
@ -788,6 +813,17 @@ public class AuthorizationInterceptorDstu2Test {
assertEquals(403, status.getStatusLine().getStatusCode());
assertFalse(ourHitMethod);
// Conditional
ourHitMethod = false;
httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
httpPost.addHeader("If-None-Exist", "Patient?foo=bar");
httpPost.setEntity(createFhirResourceEntity(createPatient(null)));
status = ourClient.execute(httpPost);
response = extractResponseAndClose(status);
assertEquals(ERR403, response);
assertEquals(403, status.getStatusLine().getStatusCode());
assertFalse(ourHitMethod);
ourHitMethod = false;
httpPost = new HttpPost("http://localhost:" + ourPort + "/Observation");
httpPost.setEntity(createFhirResourceEntity(createObservation(null, "Patient/2")));
@ -874,6 +910,16 @@ public class AuthorizationInterceptorDstu2Test {
assertEquals(201, status.getStatusLine().getStatusCode());
assertTrue(ourHitMethod);
// Conditional
ourHitMethod = false;
httpPost = new HttpPut("http://localhost:" + ourPort + "/Patient?foo=bar");
httpPost.setEntity(createFhirResourceEntity(createPatient(1)));
status = ourClient.execute(httpPost);
response = extractResponseAndClose(status);
assertEquals(ERR403, response);
assertEquals(403, status.getStatusLine().getStatusCode());
assertTrue(ourHitMethod);
ourHitMethod = false;
httpPost = new HttpPut("http://localhost:" + ourPort + "/Observation/10");
httpPost.setEntity(createFhirResourceEntity(createObservation(10, "Patient/1")));
@ -990,7 +1036,14 @@ public class AuthorizationInterceptorDstu2Test {
public static class DummyPatientResourceProvider implements IResourceProvider {
@Create()
public MethodOutcome create(@ResourceParam Patient theResource) {
public MethodOutcome create(@ResourceParam Patient theResource, @ConditionalUrlParam String theConditionalUrl, RequestDetails theRequestDetails) {
if (isNotBlank(theConditionalUrl)) {
IdDt actual = new IdDt("Patient", "1123");
ActionRequestDetails subRequest = new ActionRequestDetails(theRequestDetails, actual);
subRequest.notifyIncomingRequestPreHandled(RestOperationTypeEnum.CREATE);
}
ourHitMethod = true;
theResource.setId("Patient/1/_history/1");
MethodOutcome retVal = new MethodOutcome();
@ -999,6 +1052,7 @@ public class AuthorizationInterceptorDstu2Test {
return retVal;
}
@Delete()
public MethodOutcome delete(IRequestOperationCallback theRequestOperationCallback, @IdParam IdDt theId) {
ourHitMethod = true;
@ -1009,6 +1063,24 @@ public class AuthorizationInterceptorDstu2Test {
return retVal;
}
@Validate
public MethodOutcome validate(@ResourceParam Patient theResource, @ResourceParam String theRawResource, @ResourceParam EncodingEnum theEncoding, @Validate.Mode ValidationModeEnum theMode,
@Validate.Profile String theProfile, RequestDetails theRequestDetails) {
ourHitMethod = true;
OperationOutcome oo = new OperationOutcome();
oo.addIssue().setDiagnostics("OK");
return new MethodOutcome(oo);
}
@Validate
public MethodOutcome validate(@ResourceParam Patient theResource, @IdParam IdDt theId, @ResourceParam String theRawResource, @ResourceParam EncodingEnum theEncoding, @Validate.Mode ValidationModeEnum theMode,
@Validate.Profile String theProfile, RequestDetails theRequestDetails) {
ourHitMethod = true;
OperationOutcome oo = new OperationOutcome();
oo.addIssue().setDiagnostics("OK");
return new MethodOutcome(oo);
}
@Override
public Class<? extends IResource> getResourceType() {
return Patient.class;
@ -1027,8 +1099,15 @@ public class AuthorizationInterceptorDstu2Test {
}
@Update()
public MethodOutcome update(@IdParam IdDt theId, @ResourceParam Patient theResource) {
public MethodOutcome update(@IdParam IdDt theId, @ResourceParam Patient theResource, @ConditionalUrlParam String theConditionalUrl, RequestDetails theRequestDetails) {
ourHitMethod = true;
if (isNotBlank(theConditionalUrl)) {
IdDt actual = new IdDt("Patient", "1123");
ActionRequestDetails subRequest = new ActionRequestDetails(theRequestDetails, actual);
subRequest.notifyIncomingRequestPreHandled(RestOperationTypeEnum.UPDATE);
}
theResource.setId(theId.withVersion("2"));
MethodOutcome retVal = new MethodOutcome();
retVal.setCreated(true);

View File

@ -67,6 +67,8 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander
ValueSetExpansionOutcome vso;
try {
vso = getExpander().expand(theSource);
} catch (InvalidRequestException e) {
throw e;
} catch (Exception e) {
throw new InternalErrorException(e);
}
@ -125,7 +127,9 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander
@Override
public ValueSetExpander getExpander() {
return new ValueSetExpanderSimple(this, this);
ValueSetExpanderSimple retVal = new ValueSetExpanderSimple(this, this);
retVal.setMaxExpansionSize(Integer.MAX_VALUE);
return retVal;
}
@Override

View File

@ -70,8 +70,10 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
private Set<String> excludeKeys = new HashSet<String>();
private ValueSetExpanderFactory factory;
private ValueSet focus;
private int maxExpansionSize = 500;
private Map<String, ValueSetExpansionContainsComponent> map = new HashMap<String, ValueSet.ValueSetExpansionContainsComponent>();
private int total;
public ValueSetExpanderSimple(IWorkerContext context, ValueSetExpanderFactory factory) {
super();
@ -79,6 +81,10 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
this.factory = factory;
}
public void setMaxExpansionSize(int theMaxExpansionSize) {
maxExpansionSize = theMaxExpansionSize;
}
private void addCode(String system, String code, String display) {
ValueSetExpansionContainsComponent n = new ValueSet.ValueSetExpansionContainsComponent();
n.setSystem(system);
@ -101,7 +107,7 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
}
private void addCodes(ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params) throws ETooCostly {
if (expand.getContains().size() > 500)
if (expand.getContains().size() > maxExpansionSize)
throw new ETooCostly("Too many codes to display (>" + Integer.toString(expand.getContains().size()) + ")");
for (ValueSetExpansionParameterComponent p : expand.getParameter()) {
if (!existsInParams(params, p.getName(), p.getValue()))
@ -111,6 +117,8 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
for (ValueSetExpansionContainsComponent c : expand.getContains()) {
addCode(c.getSystem(), c.getCode(), c.getDisplay());
}
total = expand.getTotal();
}
private void excludeCode(String theSystem, String theCode) {
@ -171,6 +179,11 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
focus.getExpansion().getContains().add(c);
}
}
if (total > 0) {
focus.getExpansion().setTotal(total);
}
return new ValueSetExpansionOutcome(focus, null);
} catch (RuntimeException e) {
// TODO: we should put something more specific instead of just Exception below, since

View File

@ -386,6 +386,11 @@
create a BigDecimal from a double, resulting in weird floating point
conversions. Thanks to Craig McClendon for reporting!
</action>
<action type="fix" issue="394">
Remove the depdendency on a method from commons-lang3 3.3 which was
causing issues on some Android phones which come with an older version
of this library bundled. Thanks to Paolo Perliti for reporting!
</action>
</release>
<release version="1.5" date="2016-04-20">
<action type="fix" issue="339">

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 20 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -3,7 +3,7 @@
xmlns="http://maven.apache.org/DECORATION/1.3.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/DECORATION/1.3.0 http://maven.apache.org/xsd/decoration-1.3.0.xsd"
name="HAPI">
name="HAPI FHIR">
<!--
<bannerLeft>
@ -46,7 +46,7 @@
HAPI stylesheet comes after because it overwrites the Syntax Highlighter
font size
-->
<link rel="shortcut icon" href="http://jamesagnew.github.io/hapi-fhir/images/favicon.png" />
<link rel="shortcut icon" href="http://hapifhir.io/favicon.png" />
<link rel="stylesheet" type="text/css" href="hapi.css" />
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" />
@ -218,7 +218,7 @@
<name><![CDATA[
<span class="color-highlight">HAPI</span> FHIR
]]></name>
<href>http://jamesagnew.github.io/hapi-fhir/</href>
<href>http://hapifhir.io/</href>
</brand>
<titleTemplate>%2$s - HAPI FHIR</titleTemplate>
</reflowSkin>

View File

@ -118,23 +118,84 @@
the response from the server in order to determine whether "read" operations
are legal.
</p>
</subsection>
<subsection name="Authorizing Read Operations">
<p>
This approach has limitations however: If a request has a conditional operation,
such as a delete operation which uses a search URL, or a create operation which
uses an <code>If-None-Exist</code> header, the interceptor will not know the
actual target until the server actually processes the request.
When authorizing a read operation, the AuthorizationInterceptor
always allows client code to execute and generate a response.
It then examines the response that would be returned before
actually returning it to the client, and if rules do not permit
that data to be shown to the client the interceptor aborts the
request.
</p>
<p>
Note that there are performance implications to this mechanism,
since an unauthorized user can still cause the server to fetch data
even if they won't get to see it. This mechanism should be comprehensive
however, since it will prevent clients from using various features
in FHIR (e.g. <code>_include</code> or <code>_revinclude</code>) to
"trick" the server into showing them date they shouldn't be allowed to
see.
</p>
<p>
See the following diagram for an example of how this works.
</p>
<img src="./images/hapi_authorizationinterceptor_read_normal.svg" alt="Write Authorization"/>
</subsection>
<subsection name="Authorizing Write Operations">
<p>
Write operations (create, update, etc.) are typically authorized
by the interceptor by examining the parsed URL and making a decision
about whether to authorize the operation before allowing Resource Provider
code to proceed. This means that client code will not have a chance to execute
and create resources that the client does not have permissions to create.
</p>
<p>
See the following diagram for an example of how this works.
</p>
<img src="./images/hapi_authorizationinterceptor_write_normal.svg" alt="Write Authorization"/>
</subsection>
<subsection name="Authorizing Sub-Operations">
<p>
There are a number of situations where the REST framework doesn't
actually know exactly what operation is going to be performed by
the implementing server code. For example, if your server implements
a <code>conditional update</code> operation, the server might not know
which resource is actually being updated until the server code
is executed.
</p>
<p>
For better security, individual resource providers should notify interceptors
about their actual targets in the event of any "write" operations (create,
operations embedded in transactions, etc.)
Because client code is actually determining which resources are
being modified, the server can not automatically apply security
rules against these modifications without being provided hints
from client code.
</p>
<p>
The mechanism for doing this isn't yet fully documented, this will be improved
over the next release cycle (post 1.5). Please get in touch on our google group
if you want to help!
In this type of situation, it is important to manually
notify the interceptor chain about the "sub-operation" being performed.
The following snippet shows how to notify interceptors about
a conditional create.
</p>
<macro name="snippet">
<param name="id" value="conditionalUpdate" />
<param name="file" value="examples/src/main/java/example/AuthorizationInterceptors.java" />
</macro>
</subsection>
</section>