Merge branch 'master' of github.com:jamesagnew/hapi-fhir
This commit is contained in:
commit
8c8b7b8234
|
@ -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
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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", "");
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -147,6 +147,9 @@ public class JpaServerDemo extends RestfulServer {
|
|||
this.registerInterceptor(interceptor);
|
||||
}
|
||||
|
||||
DaoConfig daoConfig = myAppCtx.getBean(DaoConfig.class);
|
||||
daoConfig.setAllowExternalReferences(ContextHolder.isAllowExternalRefs());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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= {
|
||||
|
|
|
@ -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())) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -81,7 +81,7 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
|
|||
}
|
||||
|
||||
private ServletRequestDetails mockSrd() {
|
||||
return new ServletRequestDetails();
|
||||
return mySrd;
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -390,7 +390,7 @@ public class FhirResourceDaoDstu3SubscriptionTest extends BaseJpaDstu3Test {
|
|||
*/
|
||||
|
||||
mySystemDao.markAllResourcesForReindexing();
|
||||
mySystemDao.performReindexingPass(100, mySrd);
|
||||
mySystemDao.performReindexingPass(100);
|
||||
|
||||
assertEquals(0, mySubscriptionDao.pollForNewUndeliveredResources());
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 |
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue