Merge branch 'master' into master
This commit is contained in:
commit
60354a4cc8
|
@ -25,5 +25,5 @@ before_script:
|
||||||
script:
|
script:
|
||||||
# - mvn -e -B clean install && cd hapi-fhir-ra && mvn -e -B -DTRAVIS_JOB_ID=$TRAVIS_JOB_ID clean test jacoco:report coveralls:report
|
# - mvn -e -B clean install && cd hapi-fhir-ra && mvn -e -B -DTRAVIS_JOB_ID=$TRAVIS_JOB_ID clean test jacoco:report coveralls:report
|
||||||
# - mvn -Dci=true -e -B -P ALLMODULES,NOPARALLEL,ERRORPRONE clean install && cd hapi-fhir-jacoco && mvn -e -B -DTRAVIS_JOB_ID=$TRAVIS_JOB_ID jacoco:report coveralls:report
|
# - mvn -Dci=true -e -B -P ALLMODULES,NOPARALLEL,ERRORPRONE clean install && cd hapi-fhir-jacoco && mvn -e -B -DTRAVIS_JOB_ID=$TRAVIS_JOB_ID jacoco:report coveralls:report
|
||||||
- mvn -Dci=true -e -B -P ALLMODULES,REDUCED_JPA_TESTS,ERRORPRONE clean install && cd hapi-fhir-jacoco && mvn -e -B -DTRAVIS_JOB_ID=$TRAVIS_JOB_ID jacoco:report coveralls:report
|
- mvn -Dci=true -e -B -P ALLMODULES,REDUCED_JPA_TESTS,ERRORPRONE_JDK8 clean install && cd hapi-fhir-jacoco && mvn -e -B -DTRAVIS_JOB_ID=$TRAVIS_JOB_ID jacoco:report coveralls:report
|
||||||
|
|
||||||
|
|
|
@ -4,4 +4,4 @@ cache:
|
||||||
- C:\maven\
|
- C:\maven\
|
||||||
- C:\Users\appveyor\.m2\repository
|
- C:\Users\appveyor\.m2\repository
|
||||||
build_script:
|
build_script:
|
||||||
- cmd: mvn -P MINPARALLEL,ALLMODULES install
|
- cmd: mvn -P MINPARALLEL,ALLMODULES clean install
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
package example;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||||
|
import ca.uhn.fhir.util.ResourceReferenceInfo;
|
||||||
|
import org.hl7.fhir.dstu3.model.Bundle;
|
||||||
|
import org.hl7.fhir.dstu3.model.Resource;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class Copier {
|
||||||
|
private static final Logger ourLog = LoggerFactory.getLogger(Copier.class);
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
FhirContext ctx = FhirContext.forDstu3();
|
||||||
|
IGenericClient source = ctx.newRestfulGenericClient("http://localhost:8080/baseDstu3");
|
||||||
|
IGenericClient target = ctx.newRestfulGenericClient("https://try.smilecdr.com:8000");
|
||||||
|
|
||||||
|
List<String> resType = Arrays.asList(
|
||||||
|
"Patient", "Organization", "Encounter", "Procedure",
|
||||||
|
"Observation", "ResearchSubject", "Specimen",
|
||||||
|
"ResearchStudy", "Location", "Practitioner"
|
||||||
|
);
|
||||||
|
|
||||||
|
List<IBaseResource> queued = new ArrayList<>();
|
||||||
|
Set<String> sent = new HashSet<>();
|
||||||
|
for (String next : resType) {
|
||||||
|
copy(ctx, source, target, next, queued, sent);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (queued.size() > 0) {
|
||||||
|
ourLog.info("Have {} queued resources to deliver", queued.size());
|
||||||
|
|
||||||
|
for (IBaseResource nextQueued : new ArrayList<>(queued)) {
|
||||||
|
|
||||||
|
String missingRef = null;
|
||||||
|
for (ResourceReferenceInfo nextRefInfo : ctx.newTerser().getAllResourceReferences(nextQueued)) {
|
||||||
|
String nextRef = nextRefInfo.getResourceReference().getReferenceElement().getValue();
|
||||||
|
if (isNotBlank(nextRef) && !sent.contains(nextRef)) {
|
||||||
|
missingRef = nextRef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (missingRef != null) {
|
||||||
|
ourLog.info("Can't send {} because of missing ref {}", nextQueued.getIdElement().getIdPart(), missingRef);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
IIdType newId = target
|
||||||
|
.update()
|
||||||
|
.resource(nextQueued)
|
||||||
|
.execute()
|
||||||
|
.getId();
|
||||||
|
|
||||||
|
ourLog.info("Copied resource {} and got ID {}", nextQueued.getIdElement().getValue(), newId);
|
||||||
|
sent.add(nextQueued.getIdElement().toUnqualifiedVersionless().getValue());
|
||||||
|
queued.remove(nextQueued);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void copy(FhirContext theCtx, IGenericClient theSource, IGenericClient theTarget, String theResType, List<IBaseResource> theQueued, Set<String> theSent) {
|
||||||
|
Bundle received = theSource
|
||||||
|
.search()
|
||||||
|
.forResource(theResType)
|
||||||
|
.returnBundle(Bundle.class)
|
||||||
|
.execute();
|
||||||
|
copy(theCtx, theTarget, theResType, theQueued, theSent, received);
|
||||||
|
|
||||||
|
while (received.getLink("next") != null) {
|
||||||
|
ourLog.info("Fetching next page...");
|
||||||
|
received = theSource.loadPage().next(received).execute();
|
||||||
|
copy(theCtx, theTarget, theResType, theQueued, theSent, received);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void copy(FhirContext theCtx, IGenericClient theTarget, String theResType, List<IBaseResource> theQueued, Set<String> theSent, Bundle theReceived) {
|
||||||
|
for (Bundle.BundleEntryComponent nextEntry : theReceived.getEntry()) {
|
||||||
|
Resource nextResource = nextEntry.getResource();
|
||||||
|
nextResource.setId(theResType + "/" + "CR-" + nextResource.getIdElement().getIdPart());
|
||||||
|
|
||||||
|
boolean haveUnsentReference = false;
|
||||||
|
for (ResourceReferenceInfo nextRefInfo : theCtx.newTerser().getAllResourceReferences(nextResource)) {
|
||||||
|
IIdType nextRef = nextRefInfo.getResourceReference().getReferenceElement();
|
||||||
|
if (nextRef.hasIdPart()) {
|
||||||
|
String newRef = nextRef.getResourceType() + "/" + "CR-" + nextRef.getIdPart();
|
||||||
|
ourLog.info("Changing reference {} to {}", nextRef.getValue(), newRef);
|
||||||
|
nextRefInfo.getResourceReference().setReference(newRef);
|
||||||
|
if (!theSent.contains(newRef)) {
|
||||||
|
haveUnsentReference = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (haveUnsentReference) {
|
||||||
|
ourLog.info("Queueing {} for delivery after", nextResource.getId());
|
||||||
|
theQueued.add(nextResource);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
IIdType newId = theTarget
|
||||||
|
.update()
|
||||||
|
.resource(nextResource)
|
||||||
|
.execute()
|
||||||
|
.getId();
|
||||||
|
|
||||||
|
ourLog.info("Copied resource {} and got ID {}", nextResource.getId(), newId);
|
||||||
|
theSent.add(nextResource.getIdElement().toUnqualifiedVersionless().getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -40,16 +40,14 @@ public enum FhirVersionEnum {
|
||||||
|
|
||||||
DSTU2_1("org.hl7.fhir.dstu2016may.hapi.ctx.FhirDstu2_1", null, true, new Version("1.4.0")),
|
DSTU2_1("org.hl7.fhir.dstu2016may.hapi.ctx.FhirDstu2_1", null, true, new Version("1.4.0")),
|
||||||
|
|
||||||
DSTU3("org.hl7.fhir.dstu3.hapi.ctx.FhirDstu3", null, true, new Dstu3Version()),
|
DSTU3("org.hl7.fhir.dstu3.hapi.ctx.FhirDstu3", null, true, new Dstu3Version()),
|
||||||
|
|
||||||
R4("org.hl7.fhir.r4.hapi.ctx.FhirR4", null, true, new R4Version()),
|
R4("org.hl7.fhir.r4.hapi.ctx.FhirR4", null, true, new R4Version()),;
|
||||||
|
|
||||||
;
|
|
||||||
|
|
||||||
private final FhirVersionEnum myEquivalent;
|
private final FhirVersionEnum myEquivalent;
|
||||||
private final boolean myIsRi;
|
private final boolean myIsRi;
|
||||||
private volatile Boolean myPresentOnClasspath;
|
|
||||||
private final String myVersionClass;
|
private final String myVersionClass;
|
||||||
|
private volatile Boolean myPresentOnClasspath;
|
||||||
private volatile IFhirVersion myVersionImplementation;
|
private volatile IFhirVersion myVersionImplementation;
|
||||||
private String myFhirVersionString;
|
private String myFhirVersionString;
|
||||||
|
|
||||||
|
@ -124,15 +122,50 @@ public enum FhirVersionEnum {
|
||||||
return myIsRi;
|
return myIsRi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FhirContext newContext() {
|
||||||
|
switch (this) {
|
||||||
|
case DSTU2:
|
||||||
|
return FhirContext.forDstu2();
|
||||||
|
case DSTU2_HL7ORG:
|
||||||
|
return FhirContext.forDstu2Hl7Org();
|
||||||
|
case DSTU2_1:
|
||||||
|
return FhirContext.forDstu2_1();
|
||||||
|
case DSTU3:
|
||||||
|
return FhirContext.forDstu3();
|
||||||
|
case R4:
|
||||||
|
return FhirContext.forR4();
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Unknown version: " + this); // should not happen
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link FhirVersionEnum} which corresponds to a specific version of
|
||||||
|
* FHIR. Partial version strings (e.g. "3.0") are acceptable.
|
||||||
|
*
|
||||||
|
* @return Returns null if no version exists matching the given string
|
||||||
|
*/
|
||||||
|
public static FhirVersionEnum forVersionString(String theVersionString) {
|
||||||
|
for (FhirVersionEnum next : values()) {
|
||||||
|
if (next.getFhirVersionString().startsWith(theVersionString)) {
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface IVersionProvider {
|
||||||
|
String provideVersion();
|
||||||
|
}
|
||||||
|
|
||||||
private static class Version implements IVersionProvider {
|
private static class Version implements IVersionProvider {
|
||||||
|
|
||||||
|
private String myVersion;
|
||||||
|
|
||||||
public Version(String theVersion) {
|
public Version(String theVersion) {
|
||||||
super();
|
super();
|
||||||
myVersion = theVersion;
|
myVersion = theVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String myVersion;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String provideVersion() {
|
public String provideVersion() {
|
||||||
return myVersion;
|
return myVersion;
|
||||||
|
@ -140,18 +173,15 @@ public enum FhirVersionEnum {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private interface IVersionProvider {
|
|
||||||
String provideVersion();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class attempts to read the FHIR version from the actual model
|
* This class attempts to read the FHIR version from the actual model
|
||||||
* classes in order to supply an accurate version string even over time
|
* classes in order to supply an accurate version string even over time
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
private static class Dstu3Version implements IVersionProvider {
|
private static class Dstu3Version implements IVersionProvider {
|
||||||
|
|
||||||
public Dstu3Version() {
|
private String myVersion;
|
||||||
|
|
||||||
|
Dstu3Version() {
|
||||||
try {
|
try {
|
||||||
Class<?> c = Class.forName("org.hl7.fhir.dstu3.model.Constants");
|
Class<?> c = Class.forName("org.hl7.fhir.dstu3.model.Constants");
|
||||||
myVersion = (String) c.getDeclaredField("VERSION").get(null);
|
myVersion = (String) c.getDeclaredField("VERSION").get(null);
|
||||||
|
@ -160,8 +190,6 @@ public enum FhirVersionEnum {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String myVersion;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String provideVersion() {
|
public String provideVersion() {
|
||||||
return myVersion;
|
return myVersion;
|
||||||
|
@ -171,7 +199,9 @@ public enum FhirVersionEnum {
|
||||||
|
|
||||||
private static class R4Version implements IVersionProvider {
|
private static class R4Version implements IVersionProvider {
|
||||||
|
|
||||||
public R4Version() {
|
private String myVersion;
|
||||||
|
|
||||||
|
R4Version() {
|
||||||
try {
|
try {
|
||||||
Class<?> c = Class.forName("org.hl7.fhir.r4.model.Constants");
|
Class<?> c = Class.forName("org.hl7.fhir.r4.model.Constants");
|
||||||
myVersion = (String) c.getDeclaredField("VERSION").get(null);
|
myVersion = (String) c.getDeclaredField("VERSION").get(null);
|
||||||
|
@ -180,8 +210,6 @@ public enum FhirVersionEnum {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String myVersion;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String provideVersion() {
|
public String provideVersion() {
|
||||||
return myVersion;
|
return myVersion;
|
||||||
|
|
|
@ -19,18 +19,6 @@ package ca.uhn.fhir.model.api;
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
||||||
import ca.uhn.fhir.model.primitive.DecimalDt;
|
import ca.uhn.fhir.model.primitive.DecimalDt;
|
||||||
|
@ -39,6 +27,14 @@ import ca.uhn.fhir.model.primitive.InstantDt;
|
||||||
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
|
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
|
||||||
import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
|
import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||||
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keys in this map refer to <b>resource metadata keys</b>, which are keys used to access information about specific resource instances that live outside of the resource body. Typically, these are
|
* Keys in this map refer to <b>resource metadata keys</b>, which are keys used to access information about specific resource instances that live outside of the resource body. Typically, these are
|
||||||
|
@ -64,8 +60,6 @@ import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
*/
|
*/
|
||||||
public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If present and populated with a date/time (as an instance of {@link InstantDt}), this value is an indication that the resource is in the deleted state. This key is only used in a limited number
|
* If present and populated with a date/time (as an instance of {@link InstantDt}), this value is an indication that the resource is in the deleted state. This key is only used in a limited number
|
||||||
* of scenarios, such as POSTing transaction bundles to a server, or returning resource history.
|
* of scenarios, such as POSTing transaction bundles to a server, or returning resource history.
|
||||||
|
@ -81,23 +75,22 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
return getInstantFromMetadataOrNullIfNone(theResource.getResourceMetadata(), DELETED_AT);
|
return getInstantFromMetadataOrNullIfNone(theResource.getResourceMetadata(), DELETED_AT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void put(IResource theResource, InstantDt theObject) {
|
|
||||||
theResource.getResourceMetadata().put(DELETED_AT, theObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public IPrimitiveType<Date> get(IAnyResource theResource) {
|
public IPrimitiveType<Date> get(IAnyResource theResource) {
|
||||||
return (IPrimitiveType<Date>) theResource.getUserData(DELETED_AT.name());
|
return (IPrimitiveType<Date>) theResource.getUserData(DELETED_AT.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void put(IResource theResource, InstantDt theObject) {
|
||||||
|
theResource.getResourceMetadata().put(DELETED_AT, theObject);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void put(IAnyResource theResource, IPrimitiveType<Date> theObject) {
|
public void put(IAnyResource theResource, IPrimitiveType<Date> theObject) {
|
||||||
theResource.setUserData(DELETED_AT.name(), theObject);
|
theResource.setUserData(DELETED_AT.name(), theObject);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Denotes the search score which a given resource should match in a transaction. See the FHIR transaction definition for information about this. Corresponds to the value in
|
* Denotes the search score which a given resource should match in a transaction. See the FHIR transaction definition for information about this. Corresponds to the value in
|
||||||
* <code>Bundle.entry.score</code> in a Bundle resource.
|
* <code>Bundle.entry.score</code> in a Bundle resource.
|
||||||
|
@ -121,7 +114,6 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
theResource.getResourceMetadata().put(ENTRY_SCORE, theObject);
|
theResource.getResourceMetadata().put(ENTRY_SCORE, theObject);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If present and populated with a {@link BundleEntrySearchModeEnum}, contains the "bundle entry search mode", which is the value of the status field in the Bundle entry containing this resource.
|
* If present and populated with a {@link BundleEntrySearchModeEnum}, contains the "bundle entry search mode", which is the value of the status field in the Bundle entry containing this resource.
|
||||||
* The value for this key corresponds to field <code>Bundle.entry.search.mode</code>. This value can be set to provide a status value of "include" for included resources being returned by a
|
* The value for this key corresponds to field <code>Bundle.entry.search.mode</code>. This value can be set to provide a status value of "include" for included resources being returned by a
|
||||||
|
@ -135,27 +127,27 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
*/
|
*/
|
||||||
public static final ResourceMetadataKeySupportingAnyResource<BundleEntrySearchModeEnum, String> ENTRY_SEARCH_MODE = new ResourceMetadataKeySupportingAnyResource<BundleEntrySearchModeEnum, String>("ENTRY_SEARCH_MODE") {
|
public static final ResourceMetadataKeySupportingAnyResource<BundleEntrySearchModeEnum, String> ENTRY_SEARCH_MODE = new ResourceMetadataKeySupportingAnyResource<BundleEntrySearchModeEnum, String>("ENTRY_SEARCH_MODE") {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BundleEntrySearchModeEnum get(IResource theResource) {
|
public BundleEntrySearchModeEnum get(IResource theResource) {
|
||||||
return getEnumFromMetadataOrNullIfNone(theResource.getResourceMetadata(), ENTRY_SEARCH_MODE, BundleEntrySearchModeEnum.class, BundleEntrySearchModeEnum.VALUESET_BINDER);
|
return getEnumFromMetadataOrNullIfNone(theResource.getResourceMetadata(), ENTRY_SEARCH_MODE, BundleEntrySearchModeEnum.class, BundleEntrySearchModeEnum.VALUESET_BINDER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void put(IResource theResource, BundleEntrySearchModeEnum theObject) {
|
|
||||||
theResource.getResourceMetadata().put(ENTRY_SEARCH_MODE, theObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String get(IAnyResource theResource) {
|
public String get(IAnyResource theResource) {
|
||||||
return (String) theResource.getUserData(ENTRY_SEARCH_MODE.name());
|
return (String) theResource.getUserData(ENTRY_SEARCH_MODE.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void put(IResource theResource, BundleEntrySearchModeEnum theObject) {
|
||||||
|
theResource.getResourceMetadata().put(ENTRY_SEARCH_MODE, theObject);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void put(IAnyResource theResource, String theObject) {
|
public void put(IAnyResource theResource, String theObject) {
|
||||||
theResource.setUserData(ENTRY_SEARCH_MODE.name(), theObject);
|
theResource.setUserData(ENTRY_SEARCH_MODE.name(), theObject);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If present and populated with a {@link BundleEntryTransactionMethodEnum}, contains the "bundle entry transaction operation", which is the value of the status field in the Bundle entry
|
* If present and populated with a {@link BundleEntryTransactionMethodEnum}, contains the "bundle entry transaction operation", which is the value of the status field in the Bundle entry
|
||||||
* containing this resource. The value for this key corresponds to field <code>Bundle.entry.transaction.operation</code>. This value can be set in resources being transmitted to a server to
|
* containing this resource. The value for this key corresponds to field <code>Bundle.entry.transaction.operation</code>. This value can be set in resources being transmitted to a server to
|
||||||
|
@ -169,18 +161,13 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public static final ResourceMetadataKeySupportingAnyResource<BundleEntryTransactionMethodEnum, String> ENTRY_TRANSACTION_METHOD = new ResourceMetadataKeySupportingAnyResource<BundleEntryTransactionMethodEnum, String>(
|
public static final ResourceMetadataKeySupportingAnyResource<BundleEntryTransactionMethodEnum, String> ENTRY_TRANSACTION_METHOD = new ResourceMetadataKeySupportingAnyResource<BundleEntryTransactionMethodEnum, String>(
|
||||||
"ENTRY_TRANSACTION_OPERATION") {
|
"ENTRY_TRANSACTION_OPERATION") {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BundleEntryTransactionMethodEnum get(IResource theResource) {
|
public BundleEntryTransactionMethodEnum get(IResource theResource) {
|
||||||
return getEnumFromMetadataOrNullIfNone(theResource.getResourceMetadata(), ENTRY_TRANSACTION_METHOD, BundleEntryTransactionMethodEnum.class,
|
return getEnumFromMetadataOrNullIfNone(theResource.getResourceMetadata(), ENTRY_TRANSACTION_METHOD, BundleEntryTransactionMethodEnum.class,
|
||||||
BundleEntryTransactionMethodEnum.VALUESET_BINDER);
|
BundleEntryTransactionMethodEnum.VALUESET_BINDER);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void put(IResource theResource, BundleEntryTransactionMethodEnum theObject) {
|
|
||||||
theResource.getResourceMetadata().put(ENTRY_TRANSACTION_METHOD, theObject);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -188,13 +175,17 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
return (String) theResource.getUserData(ENTRY_TRANSACTION_METHOD.name());
|
return (String) theResource.getUserData(ENTRY_TRANSACTION_METHOD.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void put(IResource theResource, BundleEntryTransactionMethodEnum theObject) {
|
||||||
|
theResource.getResourceMetadata().put(ENTRY_TRANSACTION_METHOD, theObject);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void put(IAnyResource theResource, String theObject) {
|
public void put(IAnyResource theResource, String theObject) {
|
||||||
theResource.setUserData(ENTRY_TRANSACTION_METHOD.name(), theObject);
|
theResource.setUserData(ENTRY_TRANSACTION_METHOD.name(), theObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* If present and populated with a string, provides the "alternate link" (the link element in the bundle entry with <code>rel="alternate"</code>). Server implementations may populate this with a
|
* If present and populated with a string, provides the "alternate link" (the link element in the bundle entry with <code>rel="alternate"</code>). Server implementations may populate this with a
|
||||||
* complete URL, in which case the URL will be placed as-is in the bundle. They may alternately specify a resource relative URL (e.g. "Patient/1243") in which case the server will convert this to
|
* complete URL, in which case the URL will be placed as-is in the bundle. They may alternately specify a resource relative URL (e.g. "Patient/1243") in which case the server will convert this to
|
||||||
|
@ -205,6 +196,7 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
*/
|
*/
|
||||||
public static final ResourceMetadataKeyEnum<String> LINK_ALTERNATE = new ResourceMetadataKeyEnum<String>("LINK_ALTERNATE") {
|
public static final ResourceMetadataKeyEnum<String> LINK_ALTERNATE = new ResourceMetadataKeyEnum<String>("LINK_ALTERNATE") {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String get(IResource theResource) {
|
public String get(IResource theResource) {
|
||||||
return getStringFromMetadataOrNullIfNone(theResource.getResourceMetadata(), LINK_ALTERNATE);
|
return getStringFromMetadataOrNullIfNone(theResource.getResourceMetadata(), LINK_ALTERNATE);
|
||||||
|
@ -215,7 +207,6 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
theResource.getResourceMetadata().put(LINK_ALTERNATE, theObject);
|
theResource.getResourceMetadata().put(LINK_ALTERNATE, theObject);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If present and populated with a string, provides the "search link" (the link element in the bundle entry with <code>rel="search"</code>). Server implementations may populate this with a
|
* If present and populated with a string, provides the "search link" (the link element in the bundle entry with <code>rel="search"</code>). Server implementations may populate this with a
|
||||||
* complete URL, in which case the URL will be placed as-is in the bundle. They may alternately specify a resource relative URL (e.g. "Patient?name=tester") in which case the server will convert
|
* complete URL, in which case the URL will be placed as-is in the bundle. They may alternately specify a resource relative URL (e.g. "Patient?name=tester") in which case the server will convert
|
||||||
|
@ -226,6 +217,7 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
*/
|
*/
|
||||||
public static final ResourceMetadataKeyEnum<String> LINK_SEARCH = new ResourceMetadataKeyEnum<String>("LINK_SEARCH") {
|
public static final ResourceMetadataKeyEnum<String> LINK_SEARCH = new ResourceMetadataKeyEnum<String>("LINK_SEARCH") {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String get(IResource theResource) {
|
public String get(IResource theResource) {
|
||||||
return getStringFromMetadataOrNullIfNone(theResource.getResourceMetadata(), LINK_SEARCH);
|
return getStringFromMetadataOrNullIfNone(theResource.getResourceMetadata(), LINK_SEARCH);
|
||||||
|
@ -236,7 +228,6 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
theResource.getResourceMetadata().put(LINK_SEARCH, theObject);
|
theResource.getResourceMetadata().put(LINK_SEARCH, theObject);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The value for this key represents a previous ID used to identify this resource. This key is currently only used internally during transaction method processing.
|
* The value for this key represents a previous ID used to identify this resource. This key is currently only used internally during transaction method processing.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -245,6 +236,7 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
*/
|
*/
|
||||||
public static final ResourceMetadataKeyEnum<IdDt> PREVIOUS_ID = new ResourceMetadataKeyEnum<IdDt>("PREVIOUS_ID") {
|
public static final ResourceMetadataKeyEnum<IdDt> PREVIOUS_ID = new ResourceMetadataKeyEnum<IdDt>("PREVIOUS_ID") {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IdDt get(IResource theResource) {
|
public IdDt get(IResource theResource) {
|
||||||
return getIdFromMetadataOrNullIfNone(theResource.getResourceMetadata(), PREVIOUS_ID);
|
return getIdFromMetadataOrNullIfNone(theResource.getResourceMetadata(), PREVIOUS_ID);
|
||||||
|
@ -255,16 +247,16 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
theResource.getResourceMetadata().put(PREVIOUS_ID, theObject);
|
theResource.getResourceMetadata().put(PREVIOUS_ID, theObject);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The value for this key represents a {@link List} of profile IDs that this resource claims to conform to.
|
* The value for this key represents a {@link List} of profile IDs that this resource claims to conform to.
|
||||||
*
|
* <p>
|
||||||
* <p>
|
* <p>
|
||||||
* Values for this key are of type <b>List<IdDt></b>. Note that the returned list is <i>unmodifiable</i>, so you need to create a new list and call <code>put</code> to change its value.
|
* Values for this key are of type <b>List<IdDt></b>. Note that the returned list is <i>unmodifiable</i>, so you need to create a new list and call <code>put</code> to change its value.
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public static final ResourceMetadataKeyEnum<List<IdDt>> PROFILES = new ResourceMetadataKeyEnum<List<IdDt>>("PROFILES") {
|
public static final ResourceMetadataKeyEnum<List<IdDt>> PROFILES = new ResourceMetadataKeyEnum<List<IdDt>>("PROFILES") {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<IdDt> get(IResource theResource) {
|
public List<IdDt> get(IResource theResource) {
|
||||||
return getIdListFromMetadataOrNullIfNone(theResource.getResourceMetadata(), PROFILES);
|
return getIdListFromMetadataOrNullIfNone(theResource.getResourceMetadata(), PROFILES);
|
||||||
|
@ -275,7 +267,6 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
theResource.getResourceMetadata().put(PROFILES, theObject);
|
theResource.getResourceMetadata().put(PROFILES, theObject);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The value for this key is the bundle entry <b>Published</b> time. This is defined by FHIR as "Time resource copied into the feed", which is generally best left to the current time.
|
* The value for this key is the bundle entry <b>Published</b> time. This is defined by FHIR as "Time resource copied into the feed", which is generally best left to the current time.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -284,11 +275,12 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
* <p>
|
* <p>
|
||||||
* <b>Server Note</b>: In servers, it is generally advisable to leave this value <code>null</code>, in which case the server will substitute the current time automatically.
|
* <b>Server Note</b>: In servers, it is generally advisable to leave this value <code>null</code>, in which case the server will substitute the current time automatically.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @see InstantDt
|
* @see InstantDt
|
||||||
*/
|
*/
|
||||||
public static final ResourceMetadataKeyEnum<InstantDt> PUBLISHED = new ResourceMetadataKeyEnum<InstantDt>("PUBLISHED") {
|
public static final ResourceMetadataKeyEnum<InstantDt> PUBLISHED = new ResourceMetadataKeyEnum<InstantDt>("PUBLISHED") {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InstantDt get(IResource theResource) {
|
public InstantDt get(IResource theResource) {
|
||||||
return getInstantFromMetadataOrNullIfNone(theResource.getResourceMetadata(), PUBLISHED);
|
return getInstantFromMetadataOrNullIfNone(theResource.getResourceMetadata(), PUBLISHED);
|
||||||
|
@ -299,9 +291,9 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
theResource.getResourceMetadata().put(PUBLISHED, theObject);
|
theResource.getResourceMetadata().put(PUBLISHED, theObject);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final ResourceMetadataKeyEnum<List<BaseCodingDt>> SECURITY_LABELS = new ResourceMetadataKeyEnum<List<BaseCodingDt>>("SECURITY_LABELS") {
|
public static final ResourceMetadataKeyEnum<List<BaseCodingDt>> SECURITY_LABELS = new ResourceMetadataKeyEnum<List<BaseCodingDt>>("SECURITY_LABELS") {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<BaseCodingDt> get(IResource resource) {
|
public List<BaseCodingDt> get(IResource resource) {
|
||||||
Object obj = resource.getResourceMetadata().get(SECURITY_LABELS);
|
Object obj = resource.getResourceMetadata().get(SECURITY_LABELS);
|
||||||
|
@ -317,7 +309,7 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
return securityLabels;
|
return securityLabels;
|
||||||
} catch (ClassCastException e) {
|
} catch (ClassCastException e) {
|
||||||
throw new InternalErrorException("Found an object of type '" + obj.getClass().getCanonicalName() + "' in resource metadata for key SECURITY_LABELS - Expected "
|
throw new InternalErrorException("Found an object of type '" + obj.getClass().getCanonicalName() + "' in resource metadata for key SECURITY_LABELS - Expected "
|
||||||
+ BaseCodingDt.class.getCanonicalName());
|
+ BaseCodingDt.class.getCanonicalName());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -328,17 +320,17 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The value for this key is the list of tags associated with this resource
|
* The value for this key is the list of tags associated with this resource
|
||||||
* <p>
|
* <p>
|
||||||
* Values for this key are of type <b>{@link TagList}</b>
|
* Values for this key are of type <b>{@link TagList}</b>
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @see TagList
|
* @see TagList
|
||||||
*/
|
*/
|
||||||
public static final ResourceMetadataKeyEnum<TagList> TAG_LIST = new ResourceMetadataKeyEnum<TagList>("TAG_LIST") {
|
public static final ResourceMetadataKeyEnum<TagList> TAG_LIST = new ResourceMetadataKeyEnum<TagList>("TAG_LIST") {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TagList get(IResource theResource) {
|
public TagList get(IResource theResource) {
|
||||||
Object retValObj = theResource.getResourceMetadata().get(TAG_LIST);
|
Object retValObj = theResource.getResourceMetadata().get(TAG_LIST);
|
||||||
|
@ -351,7 +343,7 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
return (TagList) retValObj;
|
return (TagList) retValObj;
|
||||||
}
|
}
|
||||||
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + TAG_LIST.name() + " - Expected "
|
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + TAG_LIST.name() + " - Expected "
|
||||||
+ TagList.class.getCanonicalName());
|
+ TagList.class.getCanonicalName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -359,7 +351,6 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
theResource.getResourceMetadata().put(TAG_LIST, theObject);
|
theResource.getResourceMetadata().put(TAG_LIST, theObject);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If present and populated with a string (as an instance of {@link String}), this value contains the title for this resource, as supplied in any bundles containing the resource.
|
* If present and populated with a string (as an instance of {@link String}), this value contains the title for this resource, as supplied in any bundles containing the resource.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -368,6 +359,7 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
*/
|
*/
|
||||||
public static final ResourceMetadataKeyEnum<String> TITLE = new ResourceMetadataKeyEnum<String>("TITLE") {
|
public static final ResourceMetadataKeyEnum<String> TITLE = new ResourceMetadataKeyEnum<String>("TITLE") {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String get(IResource theResource) {
|
public String get(IResource theResource) {
|
||||||
return getStringFromMetadataOrNullIfNone(theResource.getResourceMetadata(), TITLE);
|
return getStringFromMetadataOrNullIfNone(theResource.getResourceMetadata(), TITLE);
|
||||||
|
@ -378,18 +370,18 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
theResource.getResourceMetadata().put(TITLE, theObject);
|
theResource.getResourceMetadata().put(TITLE, theObject);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The value for this key is the bundle entry <b>Updated</b> time. This is defined by FHIR as "Last Updated for resource". This value is also used for populating the "Last-Modified" header in the
|
* The value for this key is the bundle entry <b>Updated</b> time. This is defined by FHIR as "Last Updated for resource". This value is also used for populating the "Last-Modified" header in the
|
||||||
* case of methods that return a single resource (read, vread, etc.)
|
* case of methods that return a single resource (read, vread, etc.)
|
||||||
* <p>
|
* <p>
|
||||||
* Values for this key are of type <b>{@link InstantDt}</b>
|
* Values for this key are of type <b>{@link InstantDt}</b>
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @see InstantDt
|
* @see InstantDt
|
||||||
*/
|
*/
|
||||||
public static final ResourceMetadataKeyEnum<InstantDt> UPDATED = new ResourceMetadataKeyEnum<InstantDt>("UPDATED") {
|
public static final ResourceMetadataKeyEnum<InstantDt> UPDATED = new ResourceMetadataKeyEnum<InstantDt>("UPDATED") {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InstantDt get(IResource theResource) {
|
public InstantDt get(IResource theResource) {
|
||||||
return getInstantFromMetadataOrNullIfNone(theResource.getResourceMetadata(), UPDATED);
|
return getInstantFromMetadataOrNullIfNone(theResource.getResourceMetadata(), UPDATED);
|
||||||
|
@ -400,7 +392,6 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
theResource.getResourceMetadata().put(UPDATED, theObject);
|
theResource.getResourceMetadata().put(UPDATED, theObject);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The value for this key is the version ID of the resource object.
|
* The value for this key is the version ID of the resource object.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -409,6 +400,7 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
*/
|
*/
|
||||||
public static final ResourceMetadataKeyEnum<String> VERSION = new ResourceMetadataKeyEnum<String>("VERSION") {
|
public static final ResourceMetadataKeyEnum<String> VERSION = new ResourceMetadataKeyEnum<String>("VERSION") {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String get(IResource theResource) {
|
public String get(IResource theResource) {
|
||||||
return getStringFromMetadataOrNullIfNone(theResource.getResourceMetadata(), VERSION);
|
return getStringFromMetadataOrNullIfNone(theResource.getResourceMetadata(), VERSION);
|
||||||
|
@ -419,18 +411,18 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
theResource.getResourceMetadata().put(VERSION, theObject);
|
theResource.getResourceMetadata().put(VERSION, theObject);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The value for this key is the version ID of the resource object.
|
* The value for this key is the version ID of the resource object.
|
||||||
* <p>
|
* <p>
|
||||||
* Values for this key are of type <b>{@link IdDt}</b>
|
* Values for this key are of type <b>{@link IdDt}</b>
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @deprecated The {@link IResource#getId()} resource ID will now be populated with the version ID via the {@link IdDt#getVersionIdPart()} method
|
* @deprecated The {@link IResource#getId()} resource ID will now be populated with the version ID via the {@link IdDt#getVersionIdPart()} method
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static final ResourceMetadataKeyEnum<IdDt> VERSION_ID = new ResourceMetadataKeyEnum<IdDt>("VERSION_ID") {
|
public static final ResourceMetadataKeyEnum<IdDt> VERSION_ID = new ResourceMetadataKeyEnum<IdDt>("VERSION_ID") {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IdDt get(IResource theResource) {
|
public IdDt get(IResource theResource) {
|
||||||
return getIdFromMetadataOrNullIfNone(theResource.getResourceMetadata(), VERSION_ID);
|
return getIdFromMetadataOrNullIfNone(theResource.getResourceMetadata(), VERSION_ID);
|
||||||
|
@ -441,7 +433,7 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
theResource.getResourceMetadata().put(VERSION_ID, theObject);
|
theResource.getResourceMetadata().put(VERSION_ID, theObject);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
private final String myValue;
|
private final String myValue;
|
||||||
|
|
||||||
public ResourceMetadataKeyEnum(String theValue) {
|
public ResourceMetadataKeyEnum(String theValue) {
|
||||||
|
@ -504,12 +496,12 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
return new DecimalDt((Double) retValObj);
|
return new DecimalDt((Double) retValObj);
|
||||||
}
|
}
|
||||||
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected "
|
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected "
|
||||||
+ InstantDt.class.getCanonicalName());
|
+ InstantDt.class.getCanonicalName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private static <T extends Enum<?>> T getEnumFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum<?>, Object> theResourceMetadata, ResourceMetadataKeyEnum<T> theKey, Class<T> theEnumType,
|
private static <T extends Enum<?>> T getEnumFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum<?>, Object> theResourceMetadata, ResourceMetadataKeyEnum<T> theKey, Class<T> theEnumType,
|
||||||
IValueSetEnumBinder<T> theBinder) {
|
IValueSetEnumBinder<T> theBinder) {
|
||||||
Object retValObj = theResourceMetadata.get(theKey);
|
Object retValObj = theResourceMetadata.get(theKey);
|
||||||
if (retValObj == null) {
|
if (retValObj == null) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -519,7 +511,7 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
return theBinder.fromCodeString((String) retValObj);
|
return theBinder.fromCodeString((String) retValObj);
|
||||||
}
|
}
|
||||||
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected "
|
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected "
|
||||||
+ InstantDt.class.getCanonicalName());
|
+ InstantDt.class.getCanonicalName());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IdDt getIdFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum<?>, Object> theResourceMetadata, ResourceMetadataKeyEnum<?> theKey) {
|
private static IdDt getIdFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum<?>, Object> theResourceMetadata, ResourceMetadataKeyEnum<?> theKey) {
|
||||||
|
@ -558,11 +550,11 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
} else if (retValObj instanceof InstantDt) {
|
} else if (retValObj instanceof InstantDt) {
|
||||||
if (((InstantDt) retValObj).isEmpty()) {
|
if (((InstantDt) retValObj).isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (InstantDt) retValObj;
|
return (InstantDt) retValObj;
|
||||||
}
|
}
|
||||||
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected "
|
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected "
|
||||||
+ InstantDt.class.getCanonicalName());
|
+ InstantDt.class.getCanonicalName());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getStringFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum<?>, Object> theResourceMetadata, ResourceMetadataKeyEnum<String> theKey) {
|
private static String getStringFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum<?>, Object> theResourceMetadata, ResourceMetadataKeyEnum<String> theKey) {
|
||||||
|
@ -572,11 +564,11 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
} else if (retValObj instanceof String) {
|
} else if (retValObj instanceof String) {
|
||||||
if (StringUtils.isBlank(((String) retValObj))) {
|
if (StringUtils.isBlank(((String) retValObj))) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (String) retValObj;
|
return (String) retValObj;
|
||||||
}
|
}
|
||||||
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected "
|
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected "
|
||||||
+ String.class.getCanonicalName());
|
+ String.class.getCanonicalName());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IdDt toId(ResourceMetadataKeyEnum<?> theKey, Object retValObj) {
|
private static IdDt toId(ResourceMetadataKeyEnum<?> theKey, Object retValObj) {
|
||||||
|
@ -596,18 +588,17 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
return new IdDt(((Number) retValObj).toString());
|
return new IdDt(((Number) retValObj).toString());
|
||||||
}
|
}
|
||||||
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected "
|
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected "
|
||||||
+ IdDt.class.getCanonicalName());
|
+ IdDt.class.getCanonicalName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static abstract class ResourceMetadataKeySupportingAnyResource<T, T2> extends ResourceMetadataKeyEnum<T> {
|
public static abstract class ResourceMetadataKeySupportingAnyResource<T, T2> extends ResourceMetadataKeyEnum<T> {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
public ResourceMetadataKeySupportingAnyResource(String theValue) {
|
public ResourceMetadataKeySupportingAnyResource(String theValue) {
|
||||||
super(theValue);
|
super(theValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
|
|
||||||
public abstract T2 get(IAnyResource theResource);
|
public abstract T2 get(IAnyResource theResource);
|
||||||
|
|
||||||
public abstract void put(IAnyResource theResource, T2 theObject);
|
public abstract void put(IAnyResource theResource, T2 theObject);
|
||||||
|
|
|
@ -38,6 +38,7 @@ import java.util.*;
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
public abstract class BaseParser implements IParser {
|
public abstract class BaseParser implements IParser {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseParser.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseParser.class);
|
||||||
|
@ -156,7 +157,6 @@ public abstract class BaseParser implements IParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void containResourcesForEncoding(ContainedResources theContained, IBaseResource theResource, IBaseResource theTarget) {
|
private void containResourcesForEncoding(ContainedResources theContained, IBaseResource theResource, IBaseResource theTarget) {
|
||||||
Set<String> allIds = new HashSet<String>();
|
|
||||||
Map<String, IBaseResource> existingIdToContainedResource = null;
|
Map<String, IBaseResource> existingIdToContainedResource = null;
|
||||||
|
|
||||||
if (theTarget instanceof IResource) {
|
if (theTarget instanceof IResource) {
|
||||||
|
@ -167,9 +167,8 @@ public abstract class BaseParser implements IParser {
|
||||||
if (!nextId.startsWith("#")) {
|
if (!nextId.startsWith("#")) {
|
||||||
nextId = '#' + nextId;
|
nextId = '#' + nextId;
|
||||||
}
|
}
|
||||||
allIds.add(nextId);
|
|
||||||
if (existingIdToContainedResource == null) {
|
if (existingIdToContainedResource == null) {
|
||||||
existingIdToContainedResource = new HashMap<String, IBaseResource>();
|
existingIdToContainedResource = new HashMap<>();
|
||||||
}
|
}
|
||||||
existingIdToContainedResource.put(nextId, next);
|
existingIdToContainedResource.put(nextId, next);
|
||||||
}
|
}
|
||||||
|
@ -182,9 +181,8 @@ public abstract class BaseParser implements IParser {
|
||||||
if (!nextId.startsWith("#")) {
|
if (!nextId.startsWith("#")) {
|
||||||
nextId = '#' + nextId;
|
nextId = '#' + nextId;
|
||||||
}
|
}
|
||||||
allIds.add(nextId);
|
|
||||||
if (existingIdToContainedResource == null) {
|
if (existingIdToContainedResource == null) {
|
||||||
existingIdToContainedResource = new HashMap<String, IBaseResource>();
|
existingIdToContainedResource = new HashMap<>();
|
||||||
}
|
}
|
||||||
existingIdToContainedResource.put(nextId, next);
|
existingIdToContainedResource.put(nextId, next);
|
||||||
}
|
}
|
||||||
|
@ -480,7 +478,7 @@ public abstract class BaseParser implements IParser {
|
||||||
@Override
|
@Override
|
||||||
public void setPreferTypes(List<Class<? extends IBaseResource>> thePreferTypes) {
|
public void setPreferTypes(List<Class<? extends IBaseResource>> thePreferTypes) {
|
||||||
if (thePreferTypes != null) {
|
if (thePreferTypes != null) {
|
||||||
ArrayList<Class<? extends IBaseResource>> types = new ArrayList<Class<? extends IBaseResource>>();
|
ArrayList<Class<? extends IBaseResource>> types = new ArrayList<>();
|
||||||
for (Class<? extends IBaseResource> next : thePreferTypes) {
|
for (Class<? extends IBaseResource> next : thePreferTypes) {
|
||||||
if (Modifier.isAbstract(next.getModifiers()) == false) {
|
if (Modifier.isAbstract(next.getModifiers()) == false) {
|
||||||
types.add(next);
|
types.add(next);
|
||||||
|
@ -516,8 +514,7 @@ public abstract class BaseParser implements IParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<T> newList = new ArrayList<T>();
|
List<T> newList = new ArrayList<>(theProfiles);
|
||||||
newList.addAll(theProfiles);
|
|
||||||
|
|
||||||
BaseRuntimeElementDefinition<?> idElement = myContext.getElementDefinition("id");
|
BaseRuntimeElementDefinition<?> idElement = myContext.getElementDefinition("id");
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -1195,8 +1192,10 @@ public abstract class BaseParser implements IParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addContained(IIdType theId, IBaseResource theResource) {
|
public void addContained(IIdType theId, IBaseResource theResource) {
|
||||||
myResourceToId.put(theResource, theId);
|
if (!hasId(theId)) {
|
||||||
myResources.add(theResource);
|
myResourceToId.put(theResource, theId);
|
||||||
|
myResources.add(theResource);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<IBaseResource> getContainedResources() {
|
public List<IBaseResource> getContainedResources() {
|
||||||
|
@ -1207,6 +1206,15 @@ public abstract class BaseParser implements IParser {
|
||||||
return myResourceToId.get(theNext);
|
return myResourceToId.get(theNext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasId(IIdType theId) {
|
||||||
|
for (IIdType next : myResourceToId.values()) {
|
||||||
|
if (Objects.equals(next.getValue(), theId.getValue())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return myResourceToId.isEmpty();
|
return myResourceToId.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ public interface IParserErrorHandler {
|
||||||
void incorrectJsonType(IParseLocation theLocation, String theElementName, ValueType theExpectedValueType, ScalarType theExpectedScalarType, ValueType theFoundValueType, ScalarType theFoundScalarType);
|
void incorrectJsonType(IParseLocation theLocation, String theElementName, ValueType theExpectedValueType, ScalarType theExpectedScalarType, ValueType theFoundValueType, ScalarType theFoundScalarType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The parser detected an atttribute value that was invalid (such as: empty "" values are not permitted)
|
* The parser detected an attribute value that was invalid (such as: empty "" values are not permitted)
|
||||||
*
|
*
|
||||||
* @param theLocation
|
* @param theLocation
|
||||||
* The location in the document. Note that this may be <code>null</code> as the ParseLocation feature is experimental. Use with caution, as the API may change.
|
* The location in the document. Note that this may be <code>null</code> as the ParseLocation feature is experimental. Use with caution, as the API may change.
|
||||||
|
@ -70,7 +70,7 @@ public interface IParserErrorHandler {
|
||||||
*
|
*
|
||||||
* @param theLocation
|
* @param theLocation
|
||||||
* The location in the document. Note that this may be <code>null</code> as the ParseLocation feature is experimental. Use with caution, as the API may change.
|
* The location in the document. Note that this may be <code>null</code> as the ParseLocation feature is experimental. Use with caution, as the API may change.
|
||||||
* @param theReference The actual invalid reference (e.g. "#3")
|
* @param theElementName The missing element name
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
*/
|
*/
|
||||||
void missingRequiredElement(IParseLocation theLocation, String theElementName);
|
void missingRequiredElement(IParseLocation theLocation, String theElementName);
|
||||||
|
@ -123,7 +123,7 @@ public interface IParserErrorHandler {
|
||||||
* type which will currently always be set to null. This interface is included here so that
|
* type which will currently always be set to null. This interface is included here so that
|
||||||
* locations can be added to the API in a future release without changing the API.
|
* locations can be added to the API in a future release without changing the API.
|
||||||
*/
|
*/
|
||||||
public interface IParseLocation {
|
interface IParseLocation {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the parent element (the element containing the element currently being parsed)
|
* Returns the name of the parent element (the element containing the element currently being parsed)
|
||||||
|
|
|
@ -615,8 +615,8 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
||||||
write(theEventWriter, "resourceType", resDef.getName());
|
write(theEventWriter, "resourceType", resDef.getName());
|
||||||
if (theResourceId != null && theResourceId.hasIdPart()) {
|
if (theResourceId != null && theResourceId.hasIdPart()) {
|
||||||
write(theEventWriter, "id", theResourceId.getIdPart());
|
write(theEventWriter, "id", theResourceId.getIdPart());
|
||||||
final List<HeldExtension> extensions = new ArrayList<HeldExtension>(0);
|
final List<HeldExtension> extensions = new ArrayList<>(0);
|
||||||
final List<HeldExtension> modifierExtensions = new ArrayList<HeldExtension>(0);
|
final List<HeldExtension> modifierExtensions = new ArrayList<>(0);
|
||||||
// Undeclared extensions
|
// Undeclared extensions
|
||||||
extractUndeclaredExtensions(theResourceId, extensions, modifierExtensions, null, null);
|
extractUndeclaredExtensions(theResourceId, extensions, modifierExtensions, null, null);
|
||||||
boolean haveExtension = false;
|
boolean haveExtension = false;
|
||||||
|
@ -724,14 +724,11 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
||||||
/**
|
/**
|
||||||
* This is useful only for the two cases where extensions are encoded as direct children (e.g. not in some object
|
* This is useful only for the two cases where extensions are encoded as direct children (e.g. not in some object
|
||||||
* called _name): resource extensions, and extension extensions
|
* called _name): resource extensions, and extension extensions
|
||||||
*
|
|
||||||
* @param theChildElem
|
|
||||||
* @param theParent
|
|
||||||
*/
|
*/
|
||||||
private void extractAndWriteExtensionsAsDirectChild(IBase theElement, JsonLikeWriter theEventWriter, BaseRuntimeElementDefinition<?> theElementDef, RuntimeResourceDefinition theResDef,
|
private void extractAndWriteExtensionsAsDirectChild(IBase theElement, JsonLikeWriter theEventWriter, BaseRuntimeElementDefinition<?> theElementDef, RuntimeResourceDefinition theResDef,
|
||||||
IBaseResource theResource, CompositeChildElement theChildElem, CompositeChildElement theParent) throws IOException {
|
IBaseResource theResource, CompositeChildElement theChildElem, CompositeChildElement theParent) throws IOException {
|
||||||
List<HeldExtension> extensions = new ArrayList<HeldExtension>(0);
|
List<HeldExtension> extensions = new ArrayList<>(0);
|
||||||
List<HeldExtension> modifierExtensions = new ArrayList<HeldExtension>(0);
|
List<HeldExtension> modifierExtensions = new ArrayList<>(0);
|
||||||
|
|
||||||
// Undeclared extensions
|
// Undeclared extensions
|
||||||
extractUndeclaredExtensions(theElement, extensions, modifierExtensions, theChildElem, theParent);
|
extractUndeclaredExtensions(theElement, extensions, modifierExtensions, theChildElem, theParent);
|
||||||
|
@ -1053,7 +1050,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
||||||
} else {
|
} else {
|
||||||
parentElementName = "extension";
|
parentElementName = "extension";
|
||||||
}
|
}
|
||||||
getErrorHandler().missingRequiredElement(new ParseLocation(parentElementName), "url");
|
getErrorHandler().missingRequiredElement(new ParseLocation().setParentElementName(parentElementName), "url");
|
||||||
url = null;
|
url = null;
|
||||||
} else {
|
} else {
|
||||||
url = getExtensionUrl(jsonElement.getAsString());
|
url = getExtensionUrl(jsonElement.getAsString());
|
||||||
|
|
|
@ -29,9 +29,8 @@ class ParseLocation implements IParseLocation {
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
public ParseLocation(String theParentElementName) {
|
public ParseLocation() {
|
||||||
super();
|
super();
|
||||||
myParentElementName = theParentElementName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -39,4 +38,9 @@ class ParseLocation implements IParseLocation {
|
||||||
return myParentElementName;
|
return myParentElementName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ParseLocation setParentElementName(String theParentElementName) {
|
||||||
|
myParentElementName = theParentElementName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -806,7 +806,7 @@ class ParserState<T> {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
List<IBase> securityLabels = (List<IBase>) myMap.get(ResourceMetadataKeyEnum.SECURITY_LABELS);
|
List<IBase> securityLabels = (List<IBase>) myMap.get(ResourceMetadataKeyEnum.SECURITY_LABELS);
|
||||||
if (securityLabels == null) {
|
if (securityLabels == null) {
|
||||||
securityLabels = new ArrayList<IBase>();
|
securityLabels = new ArrayList<>();
|
||||||
myMap.put(ResourceMetadataKeyEnum.SECURITY_LABELS, securityLabels);
|
myMap.put(ResourceMetadataKeyEnum.SECURITY_LABELS, securityLabels);
|
||||||
}
|
}
|
||||||
IBase securityLabel = myContext.getVersion().newCodingDt();
|
IBase securityLabel = myContext.getVersion().newCodingDt();
|
||||||
|
|
|
@ -139,7 +139,7 @@ public class XmlParser extends BaseParser /* implements IParser */ {
|
||||||
Attribute urlAttr = elem.getAttributeByName(new QName("url"));
|
Attribute urlAttr = elem.getAttributeByName(new QName("url"));
|
||||||
String url;
|
String url;
|
||||||
if (urlAttr == null || isBlank(urlAttr.getValue())) {
|
if (urlAttr == null || isBlank(urlAttr.getValue())) {
|
||||||
getErrorHandler().missingRequiredElement(new ParseLocation("extension"), "url");
|
getErrorHandler().missingRequiredElement(new ParseLocation().setParentElementName("extension"), "url");
|
||||||
url = null;
|
url = null;
|
||||||
} else {
|
} else {
|
||||||
url = urlAttr.getValue();
|
url = urlAttr.getValue();
|
||||||
|
@ -149,7 +149,7 @@ public class XmlParser extends BaseParser /* implements IParser */ {
|
||||||
Attribute urlAttr = elem.getAttributeByName(new QName("url"));
|
Attribute urlAttr = elem.getAttributeByName(new QName("url"));
|
||||||
String url;
|
String url;
|
||||||
if (urlAttr == null || isBlank(urlAttr.getValue())) {
|
if (urlAttr == null || isBlank(urlAttr.getValue())) {
|
||||||
getErrorHandler().missingRequiredElement(new ParseLocation("modifierExtension"), "url");
|
getErrorHandler().missingRequiredElement(new ParseLocation().setParentElementName("modifierExtension"), "url");
|
||||||
url = null;
|
url = null;
|
||||||
} else {
|
} else {
|
||||||
url = urlAttr.getValue();
|
url = urlAttr.getValue();
|
||||||
|
|
|
@ -19,12 +19,14 @@ package ca.uhn.fhir.rest.api;
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.parser.IParser;
|
import ca.uhn.fhir.parser.IParser;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public enum EncodingEnum {
|
public enum EncodingEnum {
|
||||||
|
|
||||||
|
@ -40,39 +42,40 @@ public enum EncodingEnum {
|
||||||
public IParser newParser(FhirContext theContext) {
|
public IParser newParser(FhirContext theContext) {
|
||||||
return theContext.newXmlParser();
|
return theContext.newXmlParser();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
;
|
/**
|
||||||
|
* "json"
|
||||||
/** "json" */
|
*/
|
||||||
public static final String JSON_PLAIN_STRING = "json";
|
public static final String JSON_PLAIN_STRING = "json";
|
||||||
private static Map<String, EncodingEnum> ourContentTypeToEncoding;
|
/**
|
||||||
|
* "xml"
|
||||||
private static Map<String, EncodingEnum> ourContentTypeToEncodingNonLegacy;
|
*/
|
||||||
private static Map<String, EncodingEnum> ourContentTypeToEncodingStrict;
|
|
||||||
/** "xml" */
|
|
||||||
public static final String XML_PLAIN_STRING = "xml";
|
public static final String XML_PLAIN_STRING = "xml";
|
||||||
|
private static Map<String, EncodingEnum> ourContentTypeToEncoding;
|
||||||
|
private static Map<String, EncodingEnum> ourContentTypeToEncodingLegacy;
|
||||||
|
private static Map<String, EncodingEnum> ourContentTypeToEncodingStrict;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
ourContentTypeToEncoding = new HashMap<String, EncodingEnum>();
|
ourContentTypeToEncoding = new HashMap<>();
|
||||||
ourContentTypeToEncodingNonLegacy = new HashMap<String, EncodingEnum>();
|
ourContentTypeToEncodingLegacy = new HashMap<>();
|
||||||
|
|
||||||
for (EncodingEnum next : values()) {
|
for (EncodingEnum next : values()) {
|
||||||
ourContentTypeToEncoding.put(next.myResourceContentTypeNonLegacy, next);
|
ourContentTypeToEncoding.put(next.myResourceContentTypeNonLegacy, next);
|
||||||
ourContentTypeToEncoding.put(next.myResourceContentTypeLegacy, next);
|
ourContentTypeToEncoding.put(next.myResourceContentTypeLegacy, next);
|
||||||
ourContentTypeToEncodingNonLegacy.put(next.myResourceContentTypeNonLegacy, next);
|
ourContentTypeToEncodingLegacy.put(next.myResourceContentTypeLegacy, next);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* See #346
|
* See #346
|
||||||
*/
|
*/
|
||||||
ourContentTypeToEncoding.put(next.myResourceContentTypeNonLegacy.replace('+', ' '), next);
|
ourContentTypeToEncoding.put(next.myResourceContentTypeNonLegacy.replace('+', ' '), next);
|
||||||
ourContentTypeToEncoding.put(next.myResourceContentTypeLegacy.replace('+', ' '), next);
|
ourContentTypeToEncoding.put(next.myResourceContentTypeLegacy.replace('+', ' '), next);
|
||||||
ourContentTypeToEncodingNonLegacy.put(next.myResourceContentTypeNonLegacy.replace('+', ' '), next);
|
ourContentTypeToEncodingLegacy.put(next.myResourceContentTypeLegacy.replace('+', ' '), next);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add before we add the lenient ones
|
// Add before we add the lenient ones
|
||||||
ourContentTypeToEncodingStrict = Collections.unmodifiableMap(new HashMap<String, EncodingEnum>(ourContentTypeToEncoding));
|
ourContentTypeToEncodingStrict = Collections.unmodifiableMap(new HashMap<>(ourContentTypeToEncoding));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These are wrong, but we add them just to be tolerant of other
|
* These are wrong, but we add them just to be tolerant of other
|
||||||
|
@ -89,7 +92,7 @@ public enum EncodingEnum {
|
||||||
ourContentTypeToEncoding.put(JSON_PLAIN_STRING, JSON);
|
ourContentTypeToEncoding.put(JSON_PLAIN_STRING, JSON);
|
||||||
ourContentTypeToEncoding.put(XML_PLAIN_STRING, XML);
|
ourContentTypeToEncoding.put(XML_PLAIN_STRING, XML);
|
||||||
|
|
||||||
ourContentTypeToEncodingNonLegacy = Collections.unmodifiableMap(ourContentTypeToEncodingNonLegacy);
|
ourContentTypeToEncodingLegacy = Collections.unmodifiableMap(ourContentTypeToEncodingLegacy);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,10 +110,6 @@ public enum EncodingEnum {
|
||||||
return myFormatContentType;
|
return myFormatContentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getRequestContentType() {
|
|
||||||
return myFormatContentType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will return application/xml+fhir style
|
* Will return application/xml+fhir style
|
||||||
*/
|
*/
|
||||||
|
@ -150,7 +149,7 @@ public enum EncodingEnum {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the encoding for a given content type, or <code>null</code> if no encoding
|
* Returns the encoding for a given content type, or <code>null</code> if no encoding
|
||||||
* is found.
|
* is found.
|
||||||
* <p>
|
* <p>
|
||||||
* <b>This method is lenient!</b> Things like "application/xml" will return {@link EncodingEnum#XML}
|
* <b>This method is lenient!</b> Things like "application/xml" will return {@link EncodingEnum#XML}
|
||||||
* even if the "+fhir" part is missing from the expected content type.
|
* even if the "+fhir" part is missing from the expected content type.
|
||||||
|
@ -163,19 +162,23 @@ public enum EncodingEnum {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the encoding for a given content type, or <code>null</code> if no encoding
|
* Returns the encoding for a given content type, or <code>null</code> if no encoding
|
||||||
* is found.
|
* is found.
|
||||||
* <p>
|
* <p>
|
||||||
* <b>This method is NOT lenient!</b> Things like "application/xml" will return <code>null</code>
|
* <b>This method is NOT lenient!</b> Things like "application/xml" will return <code>null</code>
|
||||||
* </p>
|
* </p>
|
||||||
|
*
|
||||||
* @see #forContentType(String)
|
* @see #forContentType(String)
|
||||||
*/
|
*/
|
||||||
public static EncodingEnum forContentTypeStrict(String theContentType) {
|
public static EncodingEnum forContentTypeStrict(String theContentType) {
|
||||||
return ourContentTypeToEncodingStrict.get(theContentType);
|
return ourContentTypeToEncodingStrict.get(theContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isNonLegacy(String theFormat) {
|
/**
|
||||||
return ourContentTypeToEncodingNonLegacy.containsKey(theFormat);
|
* Is the given type a FHIR legacy (pre-DSTU3) content type?
|
||||||
|
*/
|
||||||
|
public static boolean isLegacy(String theFormat) {
|
||||||
|
return ourContentTypeToEncodingLegacy.containsKey(theFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@ package ca.uhn.fhir.rest.client.api;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
|
@ -57,7 +59,7 @@ public interface IHttpResponse {
|
||||||
* <p>
|
* <p>
|
||||||
* Buffering the message entity data allows for multiple invocations of
|
* Buffering the message entity data allows for multiple invocations of
|
||||||
* {@code readEntity(...)} methods on the response instance.
|
* {@code readEntity(...)} methods on the response instance.
|
||||||
*
|
*
|
||||||
* @since 2.2
|
* @since 2.2
|
||||||
*/
|
*/
|
||||||
void bufferEntity() throws IOException;
|
void bufferEntity() throws IOException;
|
||||||
|
@ -65,31 +67,40 @@ public interface IHttpResponse {
|
||||||
/**
|
/**
|
||||||
* Close the response
|
* Close the response
|
||||||
*/
|
*/
|
||||||
public void close();
|
void close();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returna reader for the response entity
|
* Returna reader for the response entity
|
||||||
*/
|
*/
|
||||||
public Reader createReader() throws IOException;
|
Reader createReader() throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get map of the response headers and corresponding string values.
|
* Get map of the response headers and corresponding string values.
|
||||||
*
|
*
|
||||||
* @return response headers as a map header keys and they values.
|
* @return response headers as a map header keys and they values.
|
||||||
*/
|
*/
|
||||||
public Map<String, List<String>> getAllHeaders();
|
Map<String, List<String>> getAllHeaders();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return all headers in the response with the given type
|
* Return all headers in the response with the given type
|
||||||
*/
|
*/
|
||||||
public List<String> getHeaders(String theName);
|
List<String> getHeaders(String theName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts {@code Content-Type} value from the response exactly as
|
* Extracts {@code Content-Type} value from the response exactly as
|
||||||
* specified by the {@code Content-Type} header. Returns {@code null}
|
* specified by the {@code Content-Type} header. Returns {@code null}
|
||||||
* if not specified.
|
* if not specified.
|
||||||
*/
|
*/
|
||||||
public String getMimeType();
|
String getMimeType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns a StopWatch that was started right before
|
||||||
|
* the client request was started. The time returned by this
|
||||||
|
* client includes any time that was spent within the HTTP
|
||||||
|
* library (possibly including waiting for a connection, and
|
||||||
|
* any network activity)
|
||||||
|
*/
|
||||||
|
StopWatch getRequestStopWatch();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the native response, depending on the client library used
|
* @return the native response, depending on the client library used
|
||||||
|
@ -98,21 +109,20 @@ public interface IHttpResponse {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the status code associated with the response.
|
* Get the status code associated with the response.
|
||||||
*
|
*
|
||||||
* @return the response status code.
|
* @return the response status code.
|
||||||
*/
|
*/
|
||||||
public int getStatus();
|
int getStatus();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the response status information reason phrase associated with the response.
|
* Get the response status information reason phrase associated with the response.
|
||||||
*
|
*
|
||||||
* @return the reason phrase.
|
* @return the reason phrase.
|
||||||
*/
|
*/
|
||||||
public String getStatusInfo();
|
String getStatusInfo();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the message entity input stream as an InputStream.
|
* Read the message entity input stream as an InputStream.
|
||||||
*/
|
*/
|
||||||
public InputStream readEntity() throws IOException;
|
InputStream readEntity() throws IOException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,25 +20,32 @@ package ca.uhn.fhir.rest.param;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterAnd;
|
import ca.uhn.fhir.model.api.IQueryParameterAnd;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterOr;
|
import ca.uhn.fhir.model.api.IQueryParameterOr;
|
||||||
import ca.uhn.fhir.rest.api.QualifiedParamList;
|
import ca.uhn.fhir.rest.api.QualifiedParamList;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public abstract class BaseAndListParam<T extends IQueryParameterOr<?>> implements IQueryParameterAnd<T> {
|
public abstract class BaseAndListParam<T extends IQueryParameterOr<?>> implements IQueryParameterAnd<T> {
|
||||||
|
|
||||||
private List<T> myValues=new ArrayList<T>();
|
private List<T> myValues = new ArrayList<>();
|
||||||
|
|
||||||
|
public abstract BaseAndListParam<T> addAnd(T theValue);
|
||||||
|
|
||||||
public BaseAndListParam<T> addValue(T theValue) {
|
public BaseAndListParam<T> addValue(T theValue) {
|
||||||
myValues.add(theValue);
|
myValues.add(theValue);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract BaseAndListParam<T> addAnd(T theValue);
|
@Override
|
||||||
|
public List<T> getValuesAsQueryTokens() {
|
||||||
|
return myValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract T newInstance();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setValuesAsQueryTokens(FhirContext theContext, String theParamName, List<QualifiedParamList> theParameters) throws InvalidRequestException {
|
public void setValuesAsQueryTokens(FhirContext theContext, String theParamName, List<QualifiedParamList> theParameters) throws InvalidRequestException {
|
||||||
|
@ -50,11 +57,9 @@ public abstract class BaseAndListParam<T extends IQueryParameterOr<?>> implement
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract T newInstance();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<T> getValuesAsQueryTokens() {
|
public String toString() {
|
||||||
return myValues;
|
return myValues.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -20,23 +20,35 @@ package ca.uhn.fhir.rest.param;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterOr;
|
import ca.uhn.fhir.model.api.IQueryParameterOr;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||||
import ca.uhn.fhir.rest.api.QualifiedParamList;
|
import ca.uhn.fhir.rest.api.QualifiedParamList;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
abstract class BaseOrListParam<MT extends BaseOrListParam<?, ?>, PT extends IQueryParameterType> implements IQueryParameterOr<PT> {
|
abstract class BaseOrListParam<MT extends BaseOrListParam<?, ?>, PT extends IQueryParameterType> implements IQueryParameterOr<PT> {
|
||||||
|
|
||||||
private List<PT> myList=new ArrayList<PT>();
|
private List<PT> myList = new ArrayList<>();
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public MT add(PT theParameter) {
|
||||||
|
if (theParameter != null) {
|
||||||
|
myList.add(theParameter);
|
||||||
|
}
|
||||||
|
return (MT) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract MT addOr(PT theParameter);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PT> getValuesAsQueryTokens() {
|
||||||
|
return myList;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract PT newInstance();
|
||||||
|
|
||||||
// public void addToken(T theParam) {
|
|
||||||
// Validate.notNull(theParam,"Param can not be null");
|
|
||||||
// myList.add(theParam);
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setValuesAsQueryTokens(FhirContext theContext, String theParamName, QualifiedParamList theParameters) {
|
public void setValuesAsQueryTokens(FhirContext theContext, String theParamName, QualifiedParamList theParameters) {
|
||||||
myList.clear();
|
myList.clear();
|
||||||
|
@ -47,21 +59,9 @@ abstract class BaseOrListParam<MT extends BaseOrListParam<?, ?>, PT extends IQue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract PT newInstance();
|
|
||||||
|
|
||||||
public abstract MT addOr(PT theParameter);
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public MT add(PT theParameter) {
|
|
||||||
if (theParameter != null) {
|
|
||||||
myList.add(theParameter);
|
|
||||||
}
|
|
||||||
return (MT) this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<PT> getValuesAsQueryTokens() {
|
public String toString() {
|
||||||
return myList;
|
return myList.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,5 +107,4 @@ public abstract class BaseParamWithPrefix<T extends BaseParam> extends BaseParam
|
||||||
myPrefix = thePrefix;
|
myPrefix = thePrefix;
|
||||||
return (T) this;
|
return (T) this;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,21 +20,26 @@ package ca.uhn.fhir.rest.param;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.model.api.IQueryParameterOr;
|
||||||
import java.util.*;
|
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||||
|
import ca.uhn.fhir.model.primitive.BaseDateTimeDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.DateDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||||
|
import ca.uhn.fhir.rest.api.QualifiedParamList;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
import ca.uhn.fhir.util.ValidateUtil;
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import java.util.Collections;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterOr;
|
import java.util.Date;
|
||||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
import java.util.List;
|
||||||
import ca.uhn.fhir.model.primitive.*;
|
import java.util.Objects;
|
||||||
import ca.uhn.fhir.rest.api.QualifiedParamList;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
import ca.uhn.fhir.util.ValidateUtil;
|
|
||||||
|
|
||||||
public class DateParam extends BaseParamWithPrefix<DateParam> implements /*IQueryParameterType , */IQueryParameterOr<DateParam> {
|
public class DateParam extends BaseParamWithPrefix<DateParam> implements /*IQueryParameterType , */IQueryParameterOr<DateParam> {
|
||||||
|
|
||||||
|
@ -222,6 +227,23 @@ public class DateParam extends BaseParamWithPrefix<DateParam> implements /*IQuer
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof DateParam)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DateParam other = (DateParam) obj;
|
||||||
|
return Objects.equals(getValue(), other.getValue()) &&
|
||||||
|
Objects.equals(getPrefix(), other.getPrefix());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(getValue(), getPrefix());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
@ -241,8 +263,5 @@ public class DateParam extends BaseParamWithPrefix<DateParam> implements /*IQuer
|
||||||
protected boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision) {
|
protected boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -413,6 +413,24 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof DateRangeParam)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DateRangeParam other = (DateRangeParam) obj;
|
||||||
|
return Objects.equals(myLowerBound, other.myLowerBound) &&
|
||||||
|
Objects.equals(myUpperBound, other.myUpperBound);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(myLowerBound, myUpperBound);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder b = new StringBuilder();
|
StringBuilder b = new StringBuilder();
|
||||||
|
@ -484,7 +502,5 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
|
||||||
throw new DataFormatException("Upper bound comparator must be < or <=, can not be " + myUpperBound.getPrefix().getValue());
|
throw new DataFormatException("Upper bound comparator must be < or <=, can not be " + myUpperBound.getPrefix().getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,9 +32,9 @@ import java.util.List;
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -192,10 +192,10 @@ public class ParameterUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object fromInteger(Class<?> theType, IntegerDt theArgument) {
|
public static Object fromInteger(Class<?> theType, IntegerDt theArgument) {
|
||||||
|
if (theArgument == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (theType.equals(Integer.class)) {
|
if (theType.equals(Integer.class)) {
|
||||||
if (theArgument == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return theArgument.getValue();
|
return theArgument.getValue();
|
||||||
}
|
}
|
||||||
IPrimitiveType<?> retVal = (IPrimitiveType<?>) ReflectionUtil.newInstance(theType);
|
IPrimitiveType<?> retVal = (IPrimitiveType<?>) ReflectionUtil.newInstance(theType);
|
||||||
|
|
|
@ -104,24 +104,33 @@ public class ReferenceParam extends BaseParam /*implements IQueryParameterType*/
|
||||||
void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) {
|
void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) {
|
||||||
String q = theQualifier;
|
String q = theQualifier;
|
||||||
String resourceType = null;
|
String resourceType = null;
|
||||||
|
boolean skipSetValue = false;
|
||||||
if (isNotBlank(q)) {
|
if (isNotBlank(q)) {
|
||||||
if (q.startsWith(":")) {
|
if (q.startsWith(":")) {
|
||||||
int nextIdx = q.indexOf('.');
|
int nextIdx = q.indexOf('.');
|
||||||
if (nextIdx != -1) {
|
if (nextIdx != -1) {
|
||||||
resourceType = q.substring(1, nextIdx);
|
resourceType = q.substring(1, nextIdx);
|
||||||
myChain = q.substring(nextIdx + 1);
|
myChain = q.substring(nextIdx + 1);
|
||||||
|
// type is explicitly defined so use it
|
||||||
|
myId.setParts(null, resourceType, theValue, null);
|
||||||
|
skipSetValue = true;
|
||||||
} else {
|
} else {
|
||||||
resourceType = q.substring(1);
|
resourceType = q.substring(1);
|
||||||
}
|
}
|
||||||
} else if (q.startsWith(".")) {
|
} else if (q.startsWith(".")) {
|
||||||
myChain = q.substring(1);
|
myChain = q.substring(1);
|
||||||
|
// type not defined but this is a chain, so treat value as opaque
|
||||||
|
myId.setParts(null, null, theValue, null);
|
||||||
|
skipSetValue = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setValue(theValue);
|
if (!skipSetValue) {
|
||||||
|
setValue(theValue);
|
||||||
|
|
||||||
if (isNotBlank(resourceType) && isBlank(getResourceType())) {
|
if (isNotBlank(resourceType) && isBlank(getResourceType())) {
|
||||||
setValue(resourceType + '/' + theValue);
|
setValue(resourceType + '/' + theValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,14 +69,12 @@ public class TokenOrListParam extends BaseOrListParam<TokenOrListParam, TokenPar
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a new token to this list
|
* Add a new token to this list
|
||||||
*
|
* @param theSystem
|
||||||
* @param theSystem
|
|
||||||
* The system to use for the one token to pre-populate in this list
|
* The system to use for the one token to pre-populate in this list
|
||||||
* @param theValue
|
|
||||||
* The value to use for the one token to pre-populate in this list
|
|
||||||
*/
|
*/
|
||||||
public void add(String theSystem, String theValue) {
|
public TokenOrListParam add(String theSystem, String theValue) {
|
||||||
add(new TokenParam(theSystem, theValue));
|
add(new TokenParam(theSystem, theValue));
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<BaseCodingDt> getListAsCodings() {
|
public List<BaseCodingDt> getListAsCodings() {
|
||||||
|
|
|
@ -36,6 +36,45 @@ import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||||
*/
|
*/
|
||||||
public class BundleUtil {
|
public class BundleUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns <code>null</code> if the link isn't found or has no value
|
||||||
|
*/
|
||||||
|
public static String getLinkUrlOfType(FhirContext theContext, IBaseBundle theBundle, String theLinkRelation) {
|
||||||
|
RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
|
||||||
|
BaseRuntimeChildDefinition entryChild = def.getChildByName("link");
|
||||||
|
List<IBase> links = entryChild.getAccessor().getValues(theBundle);
|
||||||
|
for (IBase nextLink : links) {
|
||||||
|
|
||||||
|
boolean isRightRel = false;
|
||||||
|
BaseRuntimeElementCompositeDefinition relDef = (BaseRuntimeElementCompositeDefinition) theContext.getElementDefinition(nextLink.getClass());
|
||||||
|
BaseRuntimeChildDefinition relChild = relDef.getChildByName("relation");
|
||||||
|
List<IBase> relValues = relChild.getAccessor().getValues(nextLink);
|
||||||
|
for (IBase next : relValues) {
|
||||||
|
IPrimitiveType<?> nextValue = (IPrimitiveType<?>)next;
|
||||||
|
if (theLinkRelation.equals(nextValue.getValueAsString())) {
|
||||||
|
isRightRel = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isRightRel) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseRuntimeElementCompositeDefinition linkDef = (BaseRuntimeElementCompositeDefinition) theContext.getElementDefinition(nextLink.getClass());
|
||||||
|
BaseRuntimeChildDefinition urlChild = linkDef.getChildByName("url");
|
||||||
|
List<IBase> values = urlChild.getAccessor().getValues(nextLink);
|
||||||
|
for (IBase nextUrl : values) {
|
||||||
|
IPrimitiveType<?> nextValue = (IPrimitiveType<?>)nextUrl;
|
||||||
|
if (isNotBlank(nextValue.getValueAsString())) {
|
||||||
|
return nextValue.getValueAsString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static List<Pair<String, IBaseResource>> getBundleEntryUrlsAndResources(FhirContext theContext, IBaseBundle theBundle) {
|
public static List<Pair<String, IBaseResource>> getBundleEntryUrlsAndResources(FhirContext theContext, IBaseBundle theBundle) {
|
||||||
RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
|
RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
|
||||||
|
@ -50,7 +89,7 @@ public class BundleUtil {
|
||||||
|
|
||||||
BaseRuntimeChildDefinition urlChild = requestDef.getChildByName("url");
|
BaseRuntimeChildDefinition urlChild = requestDef.getChildByName("url");
|
||||||
|
|
||||||
List<Pair<String, IBaseResource>> retVal = new ArrayList<Pair<String,IBaseResource>>(entries.size());
|
List<Pair<String, IBaseResource>> retVal = new ArrayList<>(entries.size());
|
||||||
for (IBase nextEntry : entries) {
|
for (IBase nextEntry : entries) {
|
||||||
|
|
||||||
String url = null;
|
String url = null;
|
||||||
|
@ -88,7 +127,7 @@ public class BundleUtil {
|
||||||
* Extract all of the resources from a given bundle
|
* Extract all of the resources from a given bundle
|
||||||
*/
|
*/
|
||||||
public static List<BundleEntryParts> toListOfEntries(FhirContext theContext, IBaseBundle theBundle) {
|
public static List<BundleEntryParts> toListOfEntries(FhirContext theContext, IBaseBundle theBundle) {
|
||||||
List<BundleEntryParts> retVal = new ArrayList<BundleEntryParts>();
|
List<BundleEntryParts> retVal = new ArrayList<>();
|
||||||
|
|
||||||
RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
|
RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
|
||||||
BaseRuntimeChildDefinition entryChild = def.getChildByName("entry");
|
BaseRuntimeChildDefinition entryChild = def.getChildByName("entry");
|
||||||
|
@ -145,7 +184,7 @@ public class BundleUtil {
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <T extends IBaseResource> List<T> toListOfResourcesOfType(FhirContext theContext, IBaseBundle theBundle, Class<T> theTypeToInclude) {
|
public static <T extends IBaseResource> List<T> toListOfResourcesOfType(FhirContext theContext, IBaseBundle theBundle, Class<T> theTypeToInclude) {
|
||||||
List<T> retVal = new ArrayList<T>();
|
List<T> retVal = new ArrayList<>();
|
||||||
|
|
||||||
RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
|
RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
|
||||||
BaseRuntimeChildDefinition entryChild = def.getChildByName("entry");
|
BaseRuntimeChildDefinition entryChild = def.getChildByName("entry");
|
||||||
|
@ -170,7 +209,7 @@ public class BundleUtil {
|
||||||
private final RequestTypeEnum myRequestType;
|
private final RequestTypeEnum myRequestType;
|
||||||
private final IBaseResource myResource;
|
private final IBaseResource myResource;
|
||||||
private final String myUrl;
|
private final String myUrl;
|
||||||
public BundleEntryParts(RequestTypeEnum theRequestType, String theUrl, IBaseResource theResource) {
|
BundleEntryParts(RequestTypeEnum theRequestType, String theUrl, IBaseResource theResource) {
|
||||||
super();
|
super();
|
||||||
myRequestType = theRequestType;
|
myRequestType = theRequestType;
|
||||||
myUrl = theUrl;
|
myUrl = theUrl;
|
||||||
|
|
|
@ -20,25 +20,23 @@ package ca.uhn.fhir.util;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.model.primitive.StringDt;
|
|
||||||
|
|
||||||
public class DatatypeUtil {
|
public class DatatypeUtil {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a list of FHIR String objects to a set of native java Strings
|
* Convert a list of FHIR String objects to a set of native java Strings
|
||||||
*/
|
*/
|
||||||
public static Set<String> toStringSet(List<StringDt> theStringList) {
|
public static Set<String> toStringSet(List<? extends IPrimitiveType<?>> theStringList) {
|
||||||
HashSet<String> retVal = new HashSet<String>();
|
HashSet<String> retVal = new HashSet<>();
|
||||||
if (theStringList != null) {
|
if (theStringList != null) {
|
||||||
for (StringDt string : theStringList) {
|
for (IPrimitiveType<?> string : theStringList) {
|
||||||
if (string != null && string.getValue()!=null) {
|
if (string != null && string.getValue()!=null) {
|
||||||
retVal.add(string.getValue());
|
retVal.add(string.getValueAsString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
package ca.uhn.fhir.util;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Core Library
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
|
import org.apache.commons.lang3.Validate;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBase;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SearchParameterUtil {
|
||||||
|
|
||||||
|
public static List<String> getBaseAsStrings(FhirContext theContext, IBaseResource theResource) {
|
||||||
|
Validate.notNull(theContext, "theContext must not be null");
|
||||||
|
Validate.notNull(theResource, "theResource must not be null");
|
||||||
|
RuntimeResourceDefinition def = theContext.getResourceDefinition(theResource);
|
||||||
|
|
||||||
|
BaseRuntimeChildDefinition base = def.getChildByName("base");
|
||||||
|
List<IBase> baseValues = base.getAccessor().getValues(theResource);
|
||||||
|
List<String> retVal = new ArrayList<>();
|
||||||
|
for (IBase next : baseValues) {
|
||||||
|
IPrimitiveType<?> nextPrimitive = (IPrimitiveType<?>) next;
|
||||||
|
retVal.add(nextPrimitive.getValueAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,202 @@
|
||||||
|
package ca.uhn.fhir.util;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
|
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
import java.text.NumberFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Core Library
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since HAPI FHIR 3.3.0
|
||||||
|
*/
|
||||||
|
public class StopWatch {
|
||||||
|
|
||||||
|
private static final NumberFormat DAY_FORMAT = new DecimalFormat("0.0");
|
||||||
|
private static final NumberFormat TEN_DAY_FORMAT = new DecimalFormat("0");
|
||||||
|
private static Long ourNowForUnitTest;
|
||||||
|
private long myStarted = now();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public StopWatch() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param theStart The time to record as the start for this timer
|
||||||
|
*/
|
||||||
|
public StopWatch(Date theStart) {
|
||||||
|
myStarted = theStart.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String formatThroughput(int theNumOperations, TimeUnit theUnit) {
|
||||||
|
double throughput = getThroughput(theNumOperations, theUnit);
|
||||||
|
return new DecimalFormat("0.0").format(throughput);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an amount of something completed so far, and a total amount, calculates how long it will take for something to complete
|
||||||
|
*
|
||||||
|
* @param theCompleteToDate The amount so far
|
||||||
|
* @param theTotal The total (must be higher than theCompleteToDate
|
||||||
|
* @return A formatted amount of time
|
||||||
|
*/
|
||||||
|
public String getEstimatedTimeRemaining(double theCompleteToDate, double theTotal) {
|
||||||
|
double millis = getMillis();
|
||||||
|
long millisRemaining = (long) (((theTotal / theCompleteToDate) * millis) - (millis));
|
||||||
|
return formatMillis(millisRemaining);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getMillis(Date theNow) {
|
||||||
|
return theNow.getTime() - myStarted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getMillis() {
|
||||||
|
long now = now();
|
||||||
|
return now - myStarted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getMillisAndRestart() {
|
||||||
|
long now = now();
|
||||||
|
long retVal = now - myStarted;
|
||||||
|
myStarted = now;
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param theNumOperations Ok for this to be 0, it will be treated as 1
|
||||||
|
*/
|
||||||
|
public int getMillisPerOperation(int theNumOperations) {
|
||||||
|
return (int) (((double) getMillis()) / Math.max(1.0, theNumOperations));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getStartedDate() {
|
||||||
|
return new Date(myStarted);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getThroughput(int theNumOperations, TimeUnit theUnit) {
|
||||||
|
if (theNumOperations <= 0) {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
long millisElapsed = Math.max(1, getMillis());
|
||||||
|
long periodMillis = theUnit.toMillis(1);
|
||||||
|
|
||||||
|
double numerator = theNumOperations;
|
||||||
|
double denominator = ((double) millisElapsed) / ((double) periodMillis);
|
||||||
|
|
||||||
|
return numerator / denominator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restart() {
|
||||||
|
myStarted = now();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats value in an appropriate format. See {@link #formatMillis(long)}}
|
||||||
|
* for a description of the format
|
||||||
|
*
|
||||||
|
* @see #formatMillis(long)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return formatMillis(getMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append a right-aligned and zero-padded numeric value to a `StringBuilder`.
|
||||||
|
*/
|
||||||
|
static private void append(StringBuilder tgt, String pfx, int dgt, long val) {
|
||||||
|
tgt.append(pfx);
|
||||||
|
if (dgt > 1) {
|
||||||
|
int pad = (dgt - 1);
|
||||||
|
for (long xa = val; xa > 9 && pad > 0; xa /= 10) {
|
||||||
|
pad--;
|
||||||
|
}
|
||||||
|
for (int xa = 0; xa < pad; xa++) {
|
||||||
|
tgt.append('0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tgt.append(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a number of milliseconds for display (e.g.
|
||||||
|
* in a log file), tailoring the output to how big
|
||||||
|
* the value actually is.
|
||||||
|
* <p>
|
||||||
|
* Example outputs:
|
||||||
|
* </p>
|
||||||
|
* <ul>
|
||||||
|
* <li>133ms</li>
|
||||||
|
* <li>00:00:10.223</li>
|
||||||
|
* <li>1.7 days</li>
|
||||||
|
* <li>64 days</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public static String formatMillis(long val) {
|
||||||
|
StringBuilder buf = new StringBuilder(20);
|
||||||
|
if (val < (10 * DateUtils.MILLIS_PER_SECOND)) {
|
||||||
|
buf.append(val);
|
||||||
|
buf.append("ms");
|
||||||
|
} else if (val >= DateUtils.MILLIS_PER_DAY) {
|
||||||
|
double days = (double) val / DateUtils.MILLIS_PER_DAY;
|
||||||
|
if (days >= 10) {
|
||||||
|
buf.append(TEN_DAY_FORMAT.format(days));
|
||||||
|
buf.append(" days");
|
||||||
|
} else if (days != 1.0f) {
|
||||||
|
buf.append(DAY_FORMAT.format(days));
|
||||||
|
buf.append(" days");
|
||||||
|
} else {
|
||||||
|
buf.append(DAY_FORMAT.format(days));
|
||||||
|
buf.append(" day");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
append(buf, "", 2, ((val % DateUtils.MILLIS_PER_DAY) / DateUtils.MILLIS_PER_HOUR));
|
||||||
|
append(buf, ":", 2, ((val % DateUtils.MILLIS_PER_HOUR) / DateUtils.MILLIS_PER_MINUTE));
|
||||||
|
append(buf, ":", 2, ((val % DateUtils.MILLIS_PER_MINUTE) / DateUtils.MILLIS_PER_SECOND));
|
||||||
|
if (val <= DateUtils.MILLIS_PER_MINUTE) {
|
||||||
|
append(buf, ".", 3, (val % DateUtils.MILLIS_PER_SECOND));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long now() {
|
||||||
|
if (ourNowForUnitTest != null) {
|
||||||
|
return ourNowForUnitTest;
|
||||||
|
}
|
||||||
|
return System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
static void setNowForUnitTestForUnitTest(Long theNowForUnitTest) {
|
||||||
|
ourNowForUnitTest = theNowForUnitTest;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package ca.uhn.fhir.util;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
||||||
|
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBase;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
import org.thymeleaf.util.Validate;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Core Library
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utilities for working with the subscription resource
|
||||||
|
*/
|
||||||
|
public class SubscriptionUtil {
|
||||||
|
|
||||||
|
private static void populatePrimitiveValue(FhirContext theContext, IBaseResource theSubscription, String theChildName, String theValue) {
|
||||||
|
RuntimeResourceDefinition def = theContext.getResourceDefinition(theSubscription);
|
||||||
|
Validate.isTrue(def.getName().equals("Subscription"), "theResource is not a subscription");
|
||||||
|
BaseRuntimeChildDefinition statusChild = def.getChildByName(theChildName);
|
||||||
|
List<IBase> entries = statusChild.getAccessor().getValues(theSubscription);
|
||||||
|
IPrimitiveType<?> instance;
|
||||||
|
if (entries.size() == 0) {
|
||||||
|
BaseRuntimeElementDefinition<?> statusElement = statusChild.getChildByName(theChildName);
|
||||||
|
instance = (IPrimitiveType<?>) statusElement.newInstance(statusChild.getInstanceConstructorArguments());
|
||||||
|
statusChild.getMutator().addValue(theSubscription, instance);
|
||||||
|
} else {
|
||||||
|
instance = (IPrimitiveType<?>) entries.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.setValueAsString(theValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setReason(FhirContext theContext, IBaseResource theSubscription, String theMessage) {
|
||||||
|
populatePrimitiveValue(theContext, theSubscription, "reason", theMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setStatus(FhirContext theContext, IBaseResource theSubscription, String theStatus) {
|
||||||
|
populatePrimitiveValue(theContext, theSubscription, "status", theStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -44,12 +44,12 @@ public interface IBaseResource extends IBase, IElement {
|
||||||
/**
|
/**
|
||||||
* Include constant for <code>*</code> (return all includes)
|
* Include constant for <code>*</code> (return all includes)
|
||||||
*/
|
*/
|
||||||
public static final Include INCLUDE_ALL = new Include("*", false).toLocked();
|
Include INCLUDE_ALL = new Include("*", false).toLocked();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Include set containing only {@link #INCLUDE_ALL}
|
* Include set containing only {@link #INCLUDE_ALL}
|
||||||
*/
|
*/
|
||||||
public static final Set<Include> WILDCARD_ALL_SET = Collections.unmodifiableSet(new HashSet<Include>(Arrays.asList(INCLUDE_ALL)));
|
Set<Include> WILDCARD_ALL_SET = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(INCLUDE_ALL)));
|
||||||
|
|
||||||
IIdType getIdElement();
|
IIdType getIdElement();
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ ca.uhn.fhir.parser.ParserState.wrongResourceTypeFound=Incorrect resource type fo
|
||||||
ca.uhn.fhir.rest.server.RestfulServer.getPagesNonHttpGet=Requests for _getpages must use HTTP GET
|
ca.uhn.fhir.rest.server.RestfulServer.getPagesNonHttpGet=Requests for _getpages must use HTTP GET
|
||||||
ca.uhn.fhir.rest.server.RestfulServer.unknownMethod=Invalid request: The FHIR endpoint on this server does not know how to handle {0} operation[{1}] with parameters [{2}]
|
ca.uhn.fhir.rest.server.RestfulServer.unknownMethod=Invalid request: The FHIR endpoint on this server does not know how to handle {0} operation[{1}] with parameters [{2}]
|
||||||
ca.uhn.fhir.rest.server.RestfulServer.rootRequest=This is the base URL of FHIR server. Unable to handle this request, as it does not contain a resource type or operation name.
|
ca.uhn.fhir.rest.server.RestfulServer.rootRequest=This is the base URL of FHIR server. Unable to handle this request, as it does not contain a resource type or operation name.
|
||||||
|
ca.uhn.fhir.rest.server.RestfulServer.rootRequest.multitenant=This is the base URL of a multitenant FHIR server. Unable to handle this request, as it does not contain a tenant ID.
|
||||||
ca.uhn.fhir.validation.ValidationContext.unableToDetermineEncoding=Unable to determine encoding (e.g. XML / JSON) on validation input. Is this a valid FHIR resource body?
|
ca.uhn.fhir.validation.ValidationContext.unableToDetermineEncoding=Unable to determine encoding (e.g. XML / JSON) on validation input. Is this a valid FHIR resource body?
|
||||||
ca.uhn.fhir.validation.FhirValidator.noPhlocWarningOnStartup=Phloc-schematron library not found on classpath, will not attempt to perform schematron validation
|
ca.uhn.fhir.validation.FhirValidator.noPhlocWarningOnStartup=Phloc-schematron library not found on classpath, will not attempt to perform schematron validation
|
||||||
ca.uhn.fhir.validation.FhirValidator.noPhlocError=Phloc-schematron library not found on classpath, can not enable perform schematron validation
|
ca.uhn.fhir.validation.FhirValidator.noPhlocError=Phloc-schematron library not found on classpath, can not enable perform schematron validation
|
||||||
|
@ -94,4 +95,3 @@ ca.uhn.fhir.jpa.term.BaseHapiTerminologySvc.cannotCreateDuplicateCodeSystemUri=C
|
||||||
ca.uhn.fhir.jpa.term.BaseHapiTerminologySvc.expansionTooLarge=Expansion of ValueSet produced too many codes (maximum {0}) - Operation aborted!
|
ca.uhn.fhir.jpa.term.BaseHapiTerminologySvc.expansionTooLarge=Expansion of ValueSet produced too many codes (maximum {0}) - Operation aborted!
|
||||||
ca.uhn.fhir.jpa.term.BaseHapiTerminologySvc.expansionTooLarge=Expansion of ValueSet produced too many codes (maximum {0}) - Operation aborted!
|
ca.uhn.fhir.jpa.term.BaseHapiTerminologySvc.expansionTooLarge=Expansion of ValueSet produced too many codes (maximum {0}) - Operation aborted!
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,195 @@
|
||||||
|
package ca.uhn.fhir.util;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
public class StopWatchTest {
|
||||||
|
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(StopWatchTest.class);
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void after() {
|
||||||
|
StopWatch.setNowForUnitTestForUnitTest(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double calculateThroughput(int theMinutesElapsed, int theNumOperations) {
|
||||||
|
StopWatch sw = new StopWatch(DateUtils.addMinutes(new Date(), -theMinutesElapsed));
|
||||||
|
double throughput = sw.getThroughput(theNumOperations, TimeUnit.MINUTES);
|
||||||
|
ourLog.info("{} operations in {}ms = {} ops / second", theNumOperations, sw.getMillis(), throughput);
|
||||||
|
return throughput;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEstimatedTimeRemainingOutOfOne() {
|
||||||
|
StopWatch.setNowForUnitTestForUnitTest(777777777L);
|
||||||
|
StopWatch sw = new StopWatch();
|
||||||
|
|
||||||
|
// Less than half
|
||||||
|
StopWatch.setNowForUnitTestForUnitTest(777777777L + DateUtils.MILLIS_PER_MINUTE);
|
||||||
|
assertEquals("00:09:00", sw.getEstimatedTimeRemaining(0.1, 1.0));
|
||||||
|
|
||||||
|
StopWatch.setNowForUnitTestForUnitTest(777777777L + DateUtils.MILLIS_PER_MINUTE);
|
||||||
|
assertEquals("00:09:00", sw.getEstimatedTimeRemaining(1, 10));
|
||||||
|
|
||||||
|
StopWatch.setNowForUnitTestForUnitTest(777777777L + DateUtils.MILLIS_PER_MINUTE + 100);
|
||||||
|
assertEquals("00:09:00", sw.getEstimatedTimeRemaining(0.1, 1.0));
|
||||||
|
|
||||||
|
StopWatch.setNowForUnitTestForUnitTest(777777777L + DateUtils.MILLIS_PER_MINUTE);
|
||||||
|
assertEquals("00:19:00", sw.getEstimatedTimeRemaining(0.05, 1.0));
|
||||||
|
|
||||||
|
StopWatch.setNowForUnitTestForUnitTest(777777777L + DateUtils.MILLIS_PER_MINUTE);
|
||||||
|
assertEquals("00:39:00", sw.getEstimatedTimeRemaining(0.025, 1.0));
|
||||||
|
|
||||||
|
// More than half
|
||||||
|
StopWatch.setNowForUnitTestForUnitTest(777777777L + DateUtils.MILLIS_PER_MINUTE);
|
||||||
|
assertEquals("00:01:00.000", sw.getEstimatedTimeRemaining(0.5, 1.0));
|
||||||
|
|
||||||
|
StopWatch.setNowForUnitTestForUnitTest(777777777L + DateUtils.MILLIS_PER_MINUTE);
|
||||||
|
assertEquals("00:00:59.760", sw.getEstimatedTimeRemaining(0.501, 1.0));
|
||||||
|
|
||||||
|
StopWatch.setNowForUnitTestForUnitTest(777777777L + DateUtils.MILLIS_PER_MINUTE);
|
||||||
|
assertEquals("00:00:40.000", sw.getEstimatedTimeRemaining(0.6, 1.0));
|
||||||
|
|
||||||
|
StopWatch.setNowForUnitTestForUnitTest(777777777L + DateUtils.MILLIS_PER_MINUTE);
|
||||||
|
assertEquals("6666ms", sw.getEstimatedTimeRemaining(0.9, 1.0));
|
||||||
|
|
||||||
|
StopWatch.setNowForUnitTestForUnitTest(777777777L + DateUtils.MILLIS_PER_MINUTE);
|
||||||
|
assertEquals("60ms", sw.getEstimatedTimeRemaining(0.999, 1.0));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEstimatedTimeRemainingOutOfOneHundred() {
|
||||||
|
StopWatch.setNowForUnitTestForUnitTest(777777777L);
|
||||||
|
StopWatch sw = new StopWatch();
|
||||||
|
|
||||||
|
StopWatch.setNowForUnitTestForUnitTest(777777777L + (10 * DateUtils.MILLIS_PER_MINUTE));
|
||||||
|
assertEquals("01:30:00", sw.getEstimatedTimeRemaining(10, 100));
|
||||||
|
|
||||||
|
StopWatch.setNowForUnitTestForUnitTest(777777777L + (DateUtils.MILLIS_PER_MINUTE));
|
||||||
|
assertEquals("00:04:00", sw.getEstimatedTimeRemaining(20, 100));
|
||||||
|
|
||||||
|
StopWatch.setNowForUnitTestForUnitTest(777777777L + (30 * DateUtils.MILLIS_PER_MINUTE));
|
||||||
|
assertEquals("01:10:00", sw.getEstimatedTimeRemaining(30, 100));
|
||||||
|
|
||||||
|
StopWatch.setNowForUnitTestForUnitTest(777777777L + (40 * DateUtils.MILLIS_PER_MINUTE));
|
||||||
|
assertEquals("01:00:00", sw.getEstimatedTimeRemaining(40, 100));
|
||||||
|
|
||||||
|
StopWatch.setNowForUnitTestForUnitTest(777777777L + (50 * DateUtils.MILLIS_PER_MINUTE));
|
||||||
|
assertEquals("00:50:00", sw.getEstimatedTimeRemaining(50, 100));
|
||||||
|
|
||||||
|
StopWatch.setNowForUnitTestForUnitTest(777777777L + (60 * DateUtils.MILLIS_PER_MINUTE));
|
||||||
|
assertEquals("00:40:00", sw.getEstimatedTimeRemaining(60, 100));
|
||||||
|
|
||||||
|
StopWatch.setNowForUnitTestForUnitTest(777777777L + (60 * DateUtils.MILLIS_PER_MINUTE));
|
||||||
|
assertEquals("00:00:36.363", sw.getEstimatedTimeRemaining(99, 100));
|
||||||
|
|
||||||
|
StopWatch.setNowForUnitTestForUnitTest(777777777L + (60 * DateUtils.MILLIS_PER_MINUTE));
|
||||||
|
assertEquals("360ms", sw.getEstimatedTimeRemaining(99.99, 100));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFormatMillis() {
|
||||||
|
assertEquals("1000ms", StopWatch.formatMillis(DateUtils.MILLIS_PER_SECOND));
|
||||||
|
assertEquals("00:01:00.000", StopWatch.formatMillis(DateUtils.MILLIS_PER_MINUTE));
|
||||||
|
assertEquals("00:01:01", StopWatch.formatMillis(DateUtils.MILLIS_PER_MINUTE + DateUtils.MILLIS_PER_SECOND));
|
||||||
|
assertEquals("01:00:00", StopWatch.formatMillis(DateUtils.MILLIS_PER_HOUR));
|
||||||
|
assertEquals("1.0 day", StopWatch.formatMillis(DateUtils.MILLIS_PER_DAY));
|
||||||
|
assertEquals("2.0 days", StopWatch.formatMillis(DateUtils.MILLIS_PER_DAY * 2));
|
||||||
|
assertEquals("2.0 days", StopWatch.formatMillis((DateUtils.MILLIS_PER_DAY * 2) + 1));
|
||||||
|
assertEquals("2.4 days", StopWatch.formatMillis((DateUtils.MILLIS_PER_DAY * 2) + (10 * DateUtils.MILLIS_PER_HOUR)));
|
||||||
|
assertEquals("11 days", StopWatch.formatMillis((DateUtils.MILLIS_PER_DAY * 11) + (10 * DateUtils.MILLIS_PER_HOUR)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFormatThroughput60Ops4Min() {
|
||||||
|
StopWatch sw = new StopWatch(DateUtils.addMinutes(new Date(), -4));
|
||||||
|
String throughput = sw.formatThroughput(60, TimeUnit.MINUTES);
|
||||||
|
ourLog.info("{} operations in {}ms = {} ops / second", 60, sw.getMillis(), throughput);
|
||||||
|
assertThat(throughput, oneOf("14.9", "15.0", "15.1", "14,9", "15,0", "15,1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMillisPerOperation() {
|
||||||
|
int minutes = 60;
|
||||||
|
StopWatch sw = new StopWatch(DateUtils.addMinutes(new Date(), -minutes));
|
||||||
|
int numOperations = 60;
|
||||||
|
int millis = sw.getMillisPerOperation(numOperations);
|
||||||
|
ourLog.info("{} operations in {}ms = {}ms / operation", numOperations, minutes * DateUtils.MILLIS_PER_MINUTE, millis);
|
||||||
|
|
||||||
|
assertThat(millis, Matchers.lessThan(62000));
|
||||||
|
assertThat(millis, Matchers.greaterThan(58000));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOperationThroughput30Ops1Min() {
|
||||||
|
double throughput = calculateThroughput(1, 30);
|
||||||
|
assertThat(throughput, greaterThan(29.0));
|
||||||
|
assertThat(throughput, lessThan(31.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOperationThroughput60Ops1Min() {
|
||||||
|
double throughput = calculateThroughput(1, 60);
|
||||||
|
assertThat(throughput, greaterThan(59.0));
|
||||||
|
assertThat(throughput, lessThan(61.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOperationThroughput60Ops4Min() {
|
||||||
|
double throughput = calculateThroughput(4, 60);
|
||||||
|
assertThat(throughput, greaterThan(14.0));
|
||||||
|
assertThat(throughput, lessThan(16.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRestart() throws InterruptedException {
|
||||||
|
StopWatch sw = new StopWatch();
|
||||||
|
Thread.sleep(500);
|
||||||
|
sw.restart();
|
||||||
|
assertThat(sw.getMillis(), lessThan(100L));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStopwatch() throws Exception {
|
||||||
|
StopWatch sw = new StopWatch();
|
||||||
|
|
||||||
|
Thread.sleep(100);
|
||||||
|
|
||||||
|
assertThat(sw.getMillis(new Date()), greaterThan(10L));
|
||||||
|
assertThat(sw.getMillis(), greaterThan(10L));
|
||||||
|
assertThat(sw.getStartedDate().getTime(), lessThan(System.currentTimeMillis()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStopwatchWithDate() throws Exception {
|
||||||
|
StopWatch sw = new StopWatch(new Date());
|
||||||
|
|
||||||
|
Thread.sleep(100);
|
||||||
|
|
||||||
|
assertThat(sw.getMillis(new Date()), greaterThan(10L));
|
||||||
|
assertThat(sw.getMillis(), greaterThan(10L));
|
||||||
|
assertThat(sw.getStartedDate().getTime(), lessThan(System.currentTimeMillis()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToString() throws Exception {
|
||||||
|
StopWatch sw = new StopWatch();
|
||||||
|
|
||||||
|
Thread.sleep(100);
|
||||||
|
|
||||||
|
String string = sw.toString();
|
||||||
|
ourLog.info(string);
|
||||||
|
assertThat(string, matchesPattern("^[0-9]{3,4}ms$"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -191,6 +191,23 @@
|
||||||
<artifactId>phloc-commons</artifactId>
|
<artifactId>phloc-commons</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
These have been added as explicit dependencies
|
||||||
|
as JDK9 no longer includes them by default
|
||||||
|
-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.xml.bind</groupId>
|
||||||
|
<artifactId>jaxb-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.xml.bind</groupId>
|
||||||
|
<artifactId>jaxb-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.xml.bind</groupId>
|
||||||
|
<artifactId>jaxb-impl</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.fusesource.jansi</groupId>
|
<groupId>org.fusesource.jansi</groupId>
|
||||||
<artifactId>jansi</artifactId>
|
<artifactId>jansi</artifactId>
|
||||||
|
|
|
@ -7,6 +7,7 @@ import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.StructureDefinition;
|
import ca.uhn.fhir.model.dstu2.resource.StructureDefinition;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.ValueSet;
|
import ca.uhn.fhir.model.dstu2.resource.ValueSet;
|
||||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
import org.apache.commons.cli.CommandLine;
|
import org.apache.commons.cli.CommandLine;
|
||||||
import org.apache.commons.cli.Option;
|
import org.apache.commons.cli.Option;
|
||||||
|
@ -163,7 +164,7 @@ public class ValidationDataUploader extends BaseCommand {
|
||||||
ValueSet next = (ValueSet) i.getResource();
|
ValueSet next = (ValueSet) i.getResource();
|
||||||
next.setId(next.getIdElement().toUnqualifiedVersionless());
|
next.setId(next.getIdElement().toUnqualifiedVersionless());
|
||||||
|
|
||||||
ourLog.info("Uploading ValueSet {}/{} : {}", new Object[]{count, total, next.getIdElement().getValue()});
|
ourLog.info("Uploading ValueSet {}/{} : {}", new Object[] {count, total, next.getIdElement().getValue()});
|
||||||
client.update().resource(next).execute();
|
client.update().resource(next).execute();
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
|
@ -182,7 +183,7 @@ public class ValidationDataUploader extends BaseCommand {
|
||||||
ValueSet next = (ValueSet) i.getResource();
|
ValueSet next = (ValueSet) i.getResource();
|
||||||
next.setId(next.getIdElement().toUnqualifiedVersionless());
|
next.setId(next.getIdElement().toUnqualifiedVersionless());
|
||||||
|
|
||||||
ourLog.info("Uploading v3-codesystems ValueSet {}/{} : {}", new Object[]{count, total, next.getIdElement().getValue()});
|
ourLog.info("Uploading v3-codesystems ValueSet {}/{} : {}", new Object[] {count, total, next.getIdElement().getValue()});
|
||||||
client.update().resource(next).execute();
|
client.update().resource(next).execute();
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
|
@ -200,7 +201,7 @@ public class ValidationDataUploader extends BaseCommand {
|
||||||
ValueSet next = (ValueSet) i.getResource();
|
ValueSet next = (ValueSet) i.getResource();
|
||||||
next.setId(next.getIdElement().toUnqualifiedVersionless());
|
next.setId(next.getIdElement().toUnqualifiedVersionless());
|
||||||
|
|
||||||
ourLog.info("Uploading v2-tables ValueSet {}/{} : {}", new Object[]{count, total, next.getIdElement().getValue()});
|
ourLog.info("Uploading v2-tables ValueSet {}/{} : {}", new Object[] {count, total, next.getIdElement().getValue()});
|
||||||
client.update().resource(next).execute();
|
client.update().resource(next).execute();
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
@ -225,7 +226,7 @@ public class ValidationDataUploader extends BaseCommand {
|
||||||
}
|
}
|
||||||
next.setId(next.getIdElement().toUnqualifiedVersionless());
|
next.setId(next.getIdElement().toUnqualifiedVersionless());
|
||||||
|
|
||||||
ourLog.info("Uploading StructureDefinition {}/{} : {}", new Object[]{count, total, next.getIdElement().getValue()});
|
ourLog.info("Uploading StructureDefinition {}/{} : {}", new Object[] {count, total, next.getIdElement().getValue()});
|
||||||
try {
|
try {
|
||||||
client.update().resource(next).execute();
|
client.update().resource(next).execute();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -268,12 +269,14 @@ public class ValidationDataUploader extends BaseCommand {
|
||||||
|
|
||||||
int bytes = ctx.newXmlParser().encodeResourceToString(next).length();
|
int bytes = ctx.newXmlParser().encodeResourceToString(next).length();
|
||||||
|
|
||||||
ourLog.info("Uploading ValueSet {}/{} : {} ({} bytes}", new Object[]{count, total, next.getIdElement().getValue(), bytes});
|
ourLog.info("Uploading ValueSet {}/{} : {} ({} bytes}", new Object[] {count, total, next.getIdElement().getValue(), bytes});
|
||||||
try {
|
try {
|
||||||
IIdType id = client.update().resource(next).execute().getId();
|
IIdType id = client.update().resource(next).execute().getId();
|
||||||
ourLog.info(" - Got ID: {}", id.getValue());
|
ourLog.info(" - Got ID: {}", id.getValue());
|
||||||
} catch (UnprocessableEntityException e) {
|
} catch (UnprocessableEntityException e) {
|
||||||
ourLog.warn("UnprocessableEntityException: " + e.toString());
|
ourLog.warn("UnprocessableEntityException: " + e.toString());
|
||||||
|
} catch (BaseServerResponseException e) {
|
||||||
|
ourLog.warn("Server responded HTTP " + e.getStatusCode() + ": " + e.toString());
|
||||||
}
|
}
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
@ -293,7 +296,7 @@ public class ValidationDataUploader extends BaseCommand {
|
||||||
org.hl7.fhir.dstu3.model.Resource next = i.getResource();
|
org.hl7.fhir.dstu3.model.Resource next = i.getResource();
|
||||||
next.setId(next.getIdElement().toUnqualifiedVersionless());
|
next.setId(next.getIdElement().toUnqualifiedVersionless());
|
||||||
|
|
||||||
ourLog.info("Uploading v3-codesystems ValueSet {}/{} : {}", new Object[]{count, total, next.getIdElement().getValue()});
|
ourLog.info("Uploading v3-codesystems ValueSet {}/{} : {}", new Object[] {count, total, next.getIdElement().getValue()});
|
||||||
try {
|
try {
|
||||||
client.update().resource(next).execute();
|
client.update().resource(next).execute();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -318,7 +321,7 @@ public class ValidationDataUploader extends BaseCommand {
|
||||||
}
|
}
|
||||||
next.setId(next.getIdElement().toUnqualifiedVersionless());
|
next.setId(next.getIdElement().toUnqualifiedVersionless());
|
||||||
|
|
||||||
ourLog.info("Uploading v2-tables ValueSet {}/{} : {}", new Object[]{count, total, next.getIdElement().getValue()});
|
ourLog.info("Uploading v2-tables ValueSet {}/{} : {}", new Object[] {count, total, next.getIdElement().getValue()});
|
||||||
client.update().resource(next).execute();
|
client.update().resource(next).execute();
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
@ -364,7 +367,7 @@ public class ValidationDataUploader extends BaseCommand {
|
||||||
|
|
||||||
int bytes = theCtx.newXmlParser().encodeResourceToString(next).length();
|
int bytes = theCtx.newXmlParser().encodeResourceToString(next).length();
|
||||||
|
|
||||||
ourLog.info("Uploading ValueSet {}/{} : {} ({} bytes}", new Object[]{count, total, next.getIdElement().getValue(), bytes});
|
ourLog.info("Uploading ValueSet {}/{} : {} ({} bytes}", new Object[] {count, total, next.getIdElement().getValue(), bytes});
|
||||||
try {
|
try {
|
||||||
IIdType id = client.update().resource(next).execute().getId();
|
IIdType id = client.update().resource(next).execute().getId();
|
||||||
ourLog.info(" - Got ID: {}", id.getValue());
|
ourLog.info(" - Got ID: {}", id.getValue());
|
||||||
|
@ -388,7 +391,7 @@ public class ValidationDataUploader extends BaseCommand {
|
||||||
org.hl7.fhir.r4.model.Resource next = i.getResource();
|
org.hl7.fhir.r4.model.Resource next = i.getResource();
|
||||||
next.setId(next.getIdElement().toUnqualifiedVersionless());
|
next.setId(next.getIdElement().toUnqualifiedVersionless());
|
||||||
|
|
||||||
ourLog.info("Uploading v3-codesystems ValueSet {}/{} : {}", new Object[]{count, total, next.getIdElement().getValue()});
|
ourLog.info("Uploading v3-codesystems ValueSet {}/{} : {}", new Object[] {count, total, next.getIdElement().getValue()});
|
||||||
client.update().resource(next).execute();
|
client.update().resource(next).execute();
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
|
@ -410,7 +413,7 @@ public class ValidationDataUploader extends BaseCommand {
|
||||||
}
|
}
|
||||||
next.setId(next.getIdElement().toUnqualifiedVersionless());
|
next.setId(next.getIdElement().toUnqualifiedVersionless());
|
||||||
|
|
||||||
ourLog.info("Uploading v2-tables ValueSet {}/{} : {}", new Object[]{count, total, next.getIdElement().getValue()});
|
ourLog.info("Uploading v2-tables ValueSet {}/{} : {}", new Object[] {count, total, next.getIdElement().getValue()});
|
||||||
client.update().resource(next).execute();
|
client.update().resource(next).execute();
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
@ -470,7 +473,7 @@ public class ValidationDataUploader extends BaseCommand {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLog.info("Uploading {} StructureDefinition {}/{} : {}", new Object[]{name, count, total, next.getIdElement().getValue()});
|
ourLog.info("Uploading {} StructureDefinition {}/{} : {}", new Object[] {name, count, total, next.getIdElement().getValue()});
|
||||||
client.update().resource(next).execute();
|
client.update().resource(next).execute();
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
|
@ -518,8 +521,12 @@ public class ValidationDataUploader extends BaseCommand {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLog.info("Uploading {} StructureDefinition {}/{} : {}", new Object[]{name, count, total, next.getIdElement().getValue()});
|
ourLog.info("Uploading {} StructureDefinition {}/{} : {}", new Object[] {name, count, total, next.getIdElement().getValue()});
|
||||||
client.update().resource(next).execute();
|
try {
|
||||||
|
client.update().resource(next).execute();
|
||||||
|
} catch (BaseServerResponseException e) {
|
||||||
|
ourLog.warn("Server responded HTTP " + e.getStatusCode() + ": " + e.toString());
|
||||||
|
}
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import java.util.Map;
|
||||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||||
import ca.uhn.fhir.rest.client.api.IHttpResponse;
|
import ca.uhn.fhir.rest.client.api.IHttpResponse;
|
||||||
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import okhttp3.Call;
|
import okhttp3.Call;
|
||||||
import okhttp3.Call.Factory;
|
import okhttp3.Call.Factory;
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
|
@ -65,9 +66,10 @@ public class OkHttpRestfulRequest implements IHttpRequest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IHttpResponse execute() throws IOException {
|
public IHttpResponse execute() throws IOException {
|
||||||
myRequestBuilder.method(getHttpVerbName(), myRequestBody);
|
StopWatch responseStopWatch = new StopWatch();
|
||||||
Call call = myClient.newCall(myRequestBuilder.build());
|
myRequestBuilder.method(getHttpVerbName(), myRequestBody);
|
||||||
return new OkHttpRestfulResponse(call.execute());
|
Call call = myClient.newCall(myRequestBuilder.build());
|
||||||
|
return new OkHttpRestfulResponse(call.execute(), responseStopWatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -4,6 +4,8 @@ import java.io.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.rest.client.impl.BaseHttpResponse;
|
||||||
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
|
@ -38,13 +40,14 @@ import okhttp3.Response;
|
||||||
*
|
*
|
||||||
* @author Matthew Clarke | matthew.clarke@orionhealth.com | Orion Health
|
* @author Matthew Clarke | matthew.clarke@orionhealth.com | Orion Health
|
||||||
*/
|
*/
|
||||||
public class OkHttpRestfulResponse implements IHttpResponse {
|
public class OkHttpRestfulResponse extends BaseHttpResponse implements IHttpResponse {
|
||||||
|
|
||||||
private boolean myEntityBuffered = false;
|
private boolean myEntityBuffered = false;
|
||||||
private byte[] myEntityBytes;
|
private byte[] myEntityBytes;
|
||||||
private Response myResponse;
|
private Response myResponse;
|
||||||
|
|
||||||
public OkHttpRestfulResponse(Response theResponse) {
|
public OkHttpRestfulResponse(Response theResponse, StopWatch theResponseStopWatch) {
|
||||||
|
super(theResponseStopWatch);
|
||||||
this.myResponse = theResponse;
|
this.myResponse = theResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,10 +27,12 @@ import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.http.Header;
|
import org.apache.http.Header;
|
||||||
import org.apache.http.HttpEntity;
|
import org.apache.http.HttpEntity;
|
||||||
import org.apache.http.HttpEntityEnclosingRequest;
|
import org.apache.http.HttpEntityEnclosingRequest;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.client.HttpClient;
|
import org.apache.http.client.HttpClient;
|
||||||
import org.apache.http.client.methods.HttpRequestBase;
|
import org.apache.http.client.methods.HttpRequestBase;
|
||||||
import org.apache.http.entity.ContentType;
|
import org.apache.http.entity.ContentType;
|
||||||
|
@ -61,7 +63,9 @@ public class ApacheHttpRequest implements IHttpRequest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IHttpResponse execute() throws IOException {
|
public IHttpResponse execute() throws IOException {
|
||||||
return new ApacheHttpResponse(myClient.execute(myRequest));
|
StopWatch responseStopWatch = new StopWatch();
|
||||||
|
HttpResponse httpResponse = myClient.execute(myRequest);
|
||||||
|
return new ApacheHttpResponse(httpResponse, responseStopWatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -23,6 +23,8 @@ import java.io.*;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.rest.client.impl.BaseHttpResponse;
|
||||||
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.http.*;
|
import org.apache.http.*;
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
@ -38,7 +40,7 @@ import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
*
|
*
|
||||||
* @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
|
* @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
|
||||||
*/
|
*/
|
||||||
public class ApacheHttpResponse implements IHttpResponse {
|
public class ApacheHttpResponse extends BaseHttpResponse implements IHttpResponse {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ApacheHttpResponse.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ApacheHttpResponse.class);
|
||||||
|
|
||||||
|
@ -46,7 +48,8 @@ public class ApacheHttpResponse implements IHttpResponse {
|
||||||
private byte[] myEntityBytes;
|
private byte[] myEntityBytes;
|
||||||
private final HttpResponse myResponse;
|
private final HttpResponse myResponse;
|
||||||
|
|
||||||
public ApacheHttpResponse(HttpResponse theResponse) {
|
public ApacheHttpResponse(HttpResponse theResponse, StopWatch theResponseStopWatch) {
|
||||||
|
super(theResponseStopWatch);
|
||||||
this.myResponse = theResponse;
|
this.myResponse = theResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package ca.uhn.fhir.rest.client.impl;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Client Framework
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.rest.client.api.IHttpResponse;
|
||||||
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
|
|
||||||
|
public abstract class BaseHttpResponse implements IHttpResponse {
|
||||||
|
private final StopWatch myRequestStopWatch;
|
||||||
|
|
||||||
|
public BaseHttpResponse(StopWatch theRequestStopWatch) {
|
||||||
|
myRequestStopWatch = theRequestStopWatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StopWatch getRequestStopWatch() {
|
||||||
|
return myRequestStopWatch;
|
||||||
|
}
|
||||||
|
}
|
|
@ -115,7 +115,9 @@ public class LoggingInterceptor implements IClientInterceptor {
|
||||||
}
|
}
|
||||||
respLocation = " (" + locationValue + ")";
|
respLocation = " (" + locationValue + ")";
|
||||||
}
|
}
|
||||||
myLog.info("Client response: {}{}", message, respLocation);
|
|
||||||
|
String timing = " in " + theResponse.getRequestStopWatch().toString();
|
||||||
|
myLog.info("Client response: {}{}{}", message, respLocation, timing);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (myLogResponseHeaders) {
|
if (myLogResponseHeaders) {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
|
@ -11,6 +12,119 @@
|
||||||
<artifactId>hapi-fhir-converter</artifactId>
|
<artifactId>hapi-fhir-converter</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-base</artifactId>
|
||||||
|
<version>3.3.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Server -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-server</artifactId>
|
||||||
|
<version>3.3.0-SNAPSHOT</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.servlet</groupId>
|
||||||
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-structures-dstu2</artifactId>
|
||||||
|
<version>3.3.0-SNAPSHOT</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
|
||||||
|
<version>3.3.0-SNAPSHOT</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-structures-dstu2.1</artifactId>
|
||||||
|
<version>3.3.0-SNAPSHOT</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-structures-dstu3</artifactId>
|
||||||
|
<version>3.3.0-SNAPSHOT</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-structures-r4</artifactId>
|
||||||
|
<version>3.3.0-SNAPSHOT</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
|
||||||
|
<version>3.3.0-SNAPSHOT</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-validation-resources-dstu3</artifactId>
|
||||||
|
<version>3.3.0-SNAPSHOT</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Testing -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-client</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.xmlunit</groupId>
|
||||||
|
<artifactId>xmlunit-core</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-servlets</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-servlet</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-server</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-util</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-webapp</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-http</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
<name>HAPI FHIR - Converter</name>
|
<name>HAPI FHIR - Converter</name>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -21,48 +135,4 @@
|
||||||
</resource>
|
</resource>
|
||||||
</resources>
|
</resources>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
|
||||||
<artifactId>hapi-fhir-base</artifactId>
|
|
||||||
<version>3.3.0-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
|
||||||
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
|
|
||||||
<version>3.3.0-SNAPSHOT</version>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
|
||||||
<artifactId>hapi-fhir-structures-dstu2.1</artifactId>
|
|
||||||
<version>3.3.0-SNAPSHOT</version>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
|
||||||
<artifactId>hapi-fhir-structures-dstu3</artifactId>
|
|
||||||
<version>3.3.0-SNAPSHOT</version>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
|
||||||
<artifactId>hapi-fhir-structures-r4</artifactId>
|
|
||||||
<version>3.3.0-SNAPSHOT</version>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
|
||||||
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
|
|
||||||
<version>3.3.0-SNAPSHOT</version>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
|
||||||
<artifactId>hapi-fhir-validation-resources-dstu3</artifactId>
|
|
||||||
<version>3.3.0-SNAPSHOT</version>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
package ca.uhn.hapi.converters.server;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Converter
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
|
import ca.uhn.fhir.rest.api.server.ResponseDetails;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
|
import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter;
|
||||||
|
import org.hl7.fhir.convertors.*;
|
||||||
|
import org.hl7.fhir.dstu3.model.Resource;
|
||||||
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>This is an experimental interceptor! Use with caution as
|
||||||
|
* behaviour may change or be removed in a future version of
|
||||||
|
* FHIR.</b>
|
||||||
|
* <p>
|
||||||
|
* This interceptor partially implements the proposed
|
||||||
|
* Versioned API features.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class VersionedApiConverterInterceptor extends InterceptorAdapter {
|
||||||
|
private final FhirContext myCtxDstu2;
|
||||||
|
private final FhirContext myCtxDstu2Hl7Org;
|
||||||
|
private VersionConvertor_30_40 myVersionConvertor_30_40;
|
||||||
|
private VersionConvertor_10_40 myVersionConvertor_10_40;
|
||||||
|
private VersionConvertor_10_30 myVersionConvertor_10_30;
|
||||||
|
|
||||||
|
public VersionedApiConverterInterceptor() {
|
||||||
|
myVersionConvertor_30_40 = new VersionConvertor_30_40();
|
||||||
|
VersionConvertorAdvisor40 advisor40 = new NullVersionConverterAdvisor40();
|
||||||
|
myVersionConvertor_10_40 = new VersionConvertor_10_40(advisor40);
|
||||||
|
VersionConvertorAdvisor30 advisor30 = new NullVersionConverterAdvisor30();
|
||||||
|
myVersionConvertor_10_30 = new VersionConvertor_10_30(advisor30);
|
||||||
|
|
||||||
|
myCtxDstu2 = FhirContext.forDstu2();
|
||||||
|
myCtxDstu2Hl7Org = FhirContext.forDstu2Hl7Org();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean outgoingResponse(RequestDetails theRequestDetails, ResponseDetails theResponseDetails, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws AuthenticationException {
|
||||||
|
String[] formatParams = theRequestDetails.getParameters().get(Constants.PARAM_FORMAT);
|
||||||
|
String accept = null;
|
||||||
|
if (formatParams != null && formatParams.length > 0) {
|
||||||
|
accept = formatParams[0];
|
||||||
|
}
|
||||||
|
if (isBlank(accept)) {
|
||||||
|
accept = defaultString(theServletRequest.getHeader(Constants.HEADER_ACCEPT));
|
||||||
|
}
|
||||||
|
StringTokenizer tok = new StringTokenizer(accept, ";");
|
||||||
|
String wantVersionString = null;
|
||||||
|
while (tok.hasMoreTokens()) {
|
||||||
|
String next = tok.nextToken().trim();
|
||||||
|
if (next.startsWith("fhirVersion=")) {
|
||||||
|
wantVersionString = next.substring("fhirVersion=".length()).trim();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FhirVersionEnum wantVersion = null;
|
||||||
|
if (isNotBlank(wantVersionString)) {
|
||||||
|
wantVersion = FhirVersionEnum.forVersionString(wantVersionString);
|
||||||
|
}
|
||||||
|
|
||||||
|
IBaseResource responseResource = theResponseDetails.getResponseResource();
|
||||||
|
FhirVersionEnum haveVersion = responseResource.getStructureFhirVersionEnum();
|
||||||
|
|
||||||
|
IBaseResource converted = null;
|
||||||
|
try {
|
||||||
|
if (wantVersion == FhirVersionEnum.R4 && haveVersion == FhirVersionEnum.DSTU3) {
|
||||||
|
converted = myVersionConvertor_30_40.convertResource(toDstu3(responseResource));
|
||||||
|
} else if (wantVersion == FhirVersionEnum.DSTU3 && haveVersion == FhirVersionEnum.R4) {
|
||||||
|
converted = myVersionConvertor_30_40.convertResource(toR4(responseResource));
|
||||||
|
} else if (wantVersion == FhirVersionEnum.DSTU2 && haveVersion == FhirVersionEnum.R4) {
|
||||||
|
converted = myVersionConvertor_10_40.convertResource(toR4(responseResource));
|
||||||
|
} else if (wantVersion == FhirVersionEnum.R4 && haveVersion == FhirVersionEnum.DSTU2) {
|
||||||
|
converted = myVersionConvertor_10_40.convertResource(toDstu2(responseResource));
|
||||||
|
} else if (wantVersion == FhirVersionEnum.DSTU2 && haveVersion == FhirVersionEnum.DSTU3) {
|
||||||
|
converted = myVersionConvertor_10_30.convertResource(toDstu3(responseResource));
|
||||||
|
} else if (wantVersion == FhirVersionEnum.DSTU3 && haveVersion == FhirVersionEnum.DSTU2) {
|
||||||
|
converted = myVersionConvertor_10_30.convertResource(toDstu2(responseResource));
|
||||||
|
}
|
||||||
|
} catch (FHIRException e) {
|
||||||
|
throw new InternalErrorException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (converted != null) {
|
||||||
|
theResponseDetails.setResponseResource(converted);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private org.hl7.fhir.instance.model.Resource toDstu2(IBaseResource theResponseResource) {
|
||||||
|
if (theResponseResource instanceof IResource) {
|
||||||
|
return (org.hl7.fhir.instance.model.Resource) myCtxDstu2Hl7Org.newJsonParser().parseResource(myCtxDstu2.newJsonParser().encodeResourceToString(theResponseResource));
|
||||||
|
}
|
||||||
|
return (org.hl7.fhir.instance.model.Resource) theResponseResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Resource toDstu3(IBaseResource theResponseResource) {
|
||||||
|
return (Resource) theResponseResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
private org.hl7.fhir.r4.model.Resource toR4(IBaseResource theResponseResource) {
|
||||||
|
return (org.hl7.fhir.r4.model.Resource) theResponseResource;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package org.hl7.fhir.convertors;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Converter
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
|
import org.hl7.fhir.instance.model.Resource;
|
||||||
|
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
|
||||||
|
import org.hl7.fhir.r4.model.CodeSystem;
|
||||||
|
import org.hl7.fhir.r4.model.ValueSet;
|
||||||
|
|
||||||
|
public class NullVersionConverterAdvisor40 implements VersionConvertorAdvisor40 {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Resource convertR2(org.hl7.fhir.r4.model.Resource resource) throws FHIRException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public org.hl7.fhir.dstu3.model.Resource convertR3(org.hl7.fhir.r4.model.Resource resource) throws FHIRException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CodeSystem getCodeSystem(ValueSet theSrc) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleCodeSystem(CodeSystem theTgtcs, ValueSet theSource) {
|
||||||
|
//nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean ignoreEntry(BundleEntryComponent theSrc) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,28 @@
|
||||||
|
package org.hl7.fhir.convertors;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Converter
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
public class VersionConvertorConstants {
|
||||||
|
|
||||||
|
public final static String MODIFIER_REASON_EXTENSION = "http://hl7.org/fhir/tooling/StructureDefinition/r4ModifierReason";
|
||||||
|
public final static String MODIFIER_REASON_LEGACY = "No Modifier Reason provideed in previous versions of FHIR";
|
||||||
|
}
|
|
@ -26,7 +26,7 @@ import java.util.List;
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import org.hl7.fhir.instance.model.CodeableConcept;
|
import org.hl7.fhir.instance.model.CodeableConcept;
|
||||||
import org.hl7.fhir.instance.model.Reference;
|
import org.hl7.fhir.instance.model.Reference;
|
||||||
import org.hl7.fhir.dstu2.utils.ToolingExtensions;
|
import org.hl7.fhir.instance.utils.ToolingExtensions;
|
||||||
import org.hl7.fhir.dstu3.conformance.ProfileUtilities;
|
import org.hl7.fhir.dstu3.conformance.ProfileUtilities;
|
||||||
import org.hl7.fhir.dstu3.model.Annotation;
|
import org.hl7.fhir.dstu3.model.Annotation;
|
||||||
import org.hl7.fhir.dstu3.model.CapabilityStatement.SystemRestfulInteraction;
|
import org.hl7.fhir.dstu3.model.CapabilityStatement.SystemRestfulInteraction;
|
||||||
|
@ -10974,7 +10974,7 @@ public class VersionConvertor_10_30 {
|
||||||
tgt.setBase(t.asStringValue());
|
tgt.setBase(t.asStringValue());
|
||||||
tgt.setType(convertSearchParamType(src.getType()));
|
tgt.setType(convertSearchParamType(src.getType()));
|
||||||
tgt.setDescription(src.getDescription());
|
tgt.setDescription(src.getDescription());
|
||||||
org.hl7.fhir.dstu2.utils.ToolingExtensions.setStringExtension(tgt, ToolingExtensions.EXT_EXPRESSION, src.getExpression());
|
org.hl7.fhir.instance.utils.ToolingExtensions.setStringExtension(tgt, ToolingExtensions.EXT_EXPRESSION, src.getExpression());
|
||||||
tgt.setXpath(src.getXpath());
|
tgt.setXpath(src.getXpath());
|
||||||
tgt.setXpathUsage(convertXPathUsageType(src.getXpathUsage()));
|
tgt.setXpathUsage(convertXPathUsageType(src.getXpathUsage()));
|
||||||
for (org.hl7.fhir.dstu3.model.CodeType t : src.getTarget())
|
for (org.hl7.fhir.dstu3.model.CodeType t : src.getTarget())
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -20,6 +20,7 @@ package org.hl7.fhir.convertors;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2011+, HL7, Inc.
|
Copyright (c) 2011+, HL7, Inc.
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
@ -54,19 +55,26 @@ package org.hl7.fhir.convertors;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hl7.fhir.dstu2016may.model.BooleanType;
|
||||||
import org.hl7.fhir.dstu2016may.model.CodeSystem.ConceptDefinitionPropertyComponent;
|
import org.hl7.fhir.dstu2016may.model.CodeSystem.ConceptDefinitionPropertyComponent;
|
||||||
|
import org.hl7.fhir.dstu2016may.model.Reference;
|
||||||
import org.hl7.fhir.dstu2016may.model.CodeableConcept;
|
import org.hl7.fhir.dstu2016may.model.CodeableConcept;
|
||||||
import org.hl7.fhir.r4.conformance.ProfileUtilities;
|
import org.hl7.fhir.r4.conformance.ProfileUtilities;
|
||||||
|
import org.hl7.fhir.r4.model.CanonicalType;
|
||||||
import org.hl7.fhir.r4.model.CodeSystem;
|
import org.hl7.fhir.r4.model.CodeSystem;
|
||||||
import org.hl7.fhir.r4.model.CodeSystem.FilterOperator;
|
import org.hl7.fhir.r4.model.CodeSystem.FilterOperator;
|
||||||
import org.hl7.fhir.r4.model.ConceptMap;
|
import org.hl7.fhir.r4.model.ConceptMap;
|
||||||
import org.hl7.fhir.r4.model.ConceptMap.ConceptMapGroupComponent;
|
import org.hl7.fhir.r4.model.ConceptMap.ConceptMapGroupComponent;
|
||||||
import org.hl7.fhir.r4.model.ConceptMap.SourceElementComponent;
|
import org.hl7.fhir.r4.model.ConceptMap.SourceElementComponent;
|
||||||
import org.hl7.fhir.r4.model.ContactDetail;
|
import org.hl7.fhir.r4.model.ContactDetail;
|
||||||
|
import org.hl7.fhir.r4.model.ElementDefinition;
|
||||||
import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionSlicingDiscriminatorComponent;
|
import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionSlicingDiscriminatorComponent;
|
||||||
import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind;
|
import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind;
|
||||||
|
import org.hl7.fhir.r4.model.StructureDefinition.TypeDerivationRule;
|
||||||
import org.hl7.fhir.r4.model.Enumeration;
|
import org.hl7.fhir.r4.model.Enumeration;
|
||||||
|
import org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemOperator;
|
||||||
import org.hl7.fhir.r4.model.Timing.EventTiming;
|
import org.hl7.fhir.r4.model.Timing.EventTiming;
|
||||||
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
import org.hl7.fhir.r4.model.UsageContext;
|
import org.hl7.fhir.r4.model.UsageContext;
|
||||||
import org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestComponent;
|
import org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestComponent;
|
||||||
import org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestResourceComponent;
|
import org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestResourceComponent;
|
||||||
|
@ -1225,7 +1233,7 @@ public class VersionConvertor_14_40 {
|
||||||
if (src.hasContentReference())
|
if (src.hasContentReference())
|
||||||
tgt.setContentReference(src.getContentReference());
|
tgt.setContentReference(src.getContentReference());
|
||||||
for (org.hl7.fhir.dstu2016may.model.ElementDefinition.TypeRefComponent t : src.getType())
|
for (org.hl7.fhir.dstu2016may.model.ElementDefinition.TypeRefComponent t : src.getType())
|
||||||
tgt.addType(convertTypeRefComponent(t));
|
convertTypeRefComponent(t, tgt.getType());
|
||||||
tgt.setDefaultValue(convertType(src.getDefaultValue()));
|
tgt.setDefaultValue(convertType(src.getDefaultValue()));
|
||||||
if (src.hasMeaningWhenMissing())
|
if (src.hasMeaningWhenMissing())
|
||||||
tgt.setMeaningWhenMissing(src.getMeaningWhenMissing());
|
tgt.setMeaningWhenMissing(src.getMeaningWhenMissing());
|
||||||
|
@ -1245,6 +1253,12 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.setMustSupport(src.getMustSupport());
|
tgt.setMustSupport(src.getMustSupport());
|
||||||
if (src.hasIsModifier())
|
if (src.hasIsModifier())
|
||||||
tgt.setIsModifier(src.getIsModifier());
|
tgt.setIsModifier(src.getIsModifier());
|
||||||
|
if (tgt.getIsModifier()) {
|
||||||
|
String reason = org.hl7.fhir.dstu2016may.utils.ToolingExtensions.readStringExtension(src, VersionConvertorConstants.MODIFIER_REASON_EXTENSION);
|
||||||
|
if (Utilities.noString(reason))
|
||||||
|
reason = VersionConvertorConstants.MODIFIER_REASON_LEGACY;
|
||||||
|
tgt.setIsModifierReason(reason);
|
||||||
|
}
|
||||||
if (src.hasIsSummary())
|
if (src.hasIsSummary())
|
||||||
tgt.setIsSummary(src.getIsSummary());
|
tgt.setIsSummary(src.getIsSummary());
|
||||||
tgt.setBinding(convertElementDefinitionBindingComponent(src.getBinding()));
|
tgt.setBinding(convertElementDefinitionBindingComponent(src.getBinding()));
|
||||||
|
@ -1288,7 +1302,7 @@ public class VersionConvertor_14_40 {
|
||||||
if (src.hasContentReference())
|
if (src.hasContentReference())
|
||||||
tgt.setContentReference(src.getContentReference());
|
tgt.setContentReference(src.getContentReference());
|
||||||
for (org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent t : src.getType())
|
for (org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent t : src.getType())
|
||||||
tgt.addType(convertTypeRefComponent(t));
|
convertTypeRefComponent(t, tgt.getType());
|
||||||
tgt.setDefaultValue(convertType(src.getDefaultValue()));
|
tgt.setDefaultValue(convertType(src.getDefaultValue()));
|
||||||
if (src.hasMeaningWhenMissing())
|
if (src.hasMeaningWhenMissing())
|
||||||
tgt.setMeaningWhenMissing(src.getMeaningWhenMissing());
|
tgt.setMeaningWhenMissing(src.getMeaningWhenMissing());
|
||||||
|
@ -1308,6 +1322,8 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.setMustSupport(src.getMustSupport());
|
tgt.setMustSupport(src.getMustSupport());
|
||||||
if (src.hasIsModifier())
|
if (src.hasIsModifier())
|
||||||
tgt.setIsModifier(src.getIsModifier());
|
tgt.setIsModifier(src.getIsModifier());
|
||||||
|
if (src.hasIsModifierReason() && !VersionConvertorConstants.MODIFIER_REASON_LEGACY.equals(src.getIsModifierReason()))
|
||||||
|
org.hl7.fhir.dstu2016may.utils.ToolingExtensions.setStringExtension(tgt, VersionConvertorConstants.MODIFIER_REASON_EXTENSION, src.getIsModifierReason());
|
||||||
if (src.hasIsSummary())
|
if (src.hasIsSummary())
|
||||||
tgt.setIsSummary(src.getIsSummary());
|
tgt.setIsSummary(src.getIsSummary());
|
||||||
if (src.hasBinding())
|
if (src.hasBinding())
|
||||||
|
@ -1438,38 +1454,51 @@ public class VersionConvertor_14_40 {
|
||||||
return tgt;
|
return tgt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent convertTypeRefComponent(org.hl7.fhir.dstu2016may.model.ElementDefinition.TypeRefComponent src) throws FHIRException {
|
static void convertTypeRefComponent(org.hl7.fhir.dstu2016may.model.ElementDefinition.TypeRefComponent src, List<org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent> list) throws FHIRException {
|
||||||
if (src == null || src.isEmpty())
|
if (src == null)
|
||||||
return null;
|
return ;
|
||||||
org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent tgt = new org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent();
|
org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent tgt = null;
|
||||||
copyElement(src, tgt);
|
for (org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent t : list)
|
||||||
tgt.setCode(src.getCode());
|
if (t.getCode().equals(src.getCode()))
|
||||||
for (org.hl7.fhir.dstu2016may.model.UriType t : src.getProfile()) {
|
tgt = t;
|
||||||
if (src.getCode().equals("Reference"))
|
if (tgt == null) {
|
||||||
tgt.setTargetProfile(t.getValueAsString());
|
tgt = new org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent();
|
||||||
else
|
list.add(tgt);
|
||||||
tgt.setProfile(t.getValueAsString());
|
copyElement(src, tgt);
|
||||||
|
tgt.setCode(src.getCode());
|
||||||
}
|
}
|
||||||
for (org.hl7.fhir.dstu2016may.model.Enumeration<org.hl7.fhir.dstu2016may.model.ElementDefinition.AggregationMode> t : src.getAggregation())
|
if (tgt.hasTarget()) {
|
||||||
tgt.addAggregation(convertAggregationMode(t.getValue()));
|
for (org.hl7.fhir.dstu2016may.model.UriType u : src.getProfile())
|
||||||
tgt.setVersioning(convertReferenceVersionRules(src.getVersioning()));
|
tgt.addTargetProfile(u.getValue());
|
||||||
return tgt;
|
} else {
|
||||||
|
for (org.hl7.fhir.dstu2016may.model.UriType u : src.getProfile())
|
||||||
|
tgt.addProfile(u.getValue());
|
||||||
|
}
|
||||||
|
for (org.hl7.fhir.dstu2016may.model.Enumeration<org.hl7.fhir.dstu2016may.model.ElementDefinition.AggregationMode> t : src.getAggregation()) {
|
||||||
|
org.hl7.fhir.r4.model.ElementDefinition.AggregationMode a = convertAggregationMode(t.getValue());
|
||||||
|
if (!tgt.hasAggregation(a))
|
||||||
|
tgt.addAggregation(a);
|
||||||
|
}
|
||||||
|
if (src.hasVersioning())
|
||||||
|
tgt.setVersioning(convertReferenceVersionRules(src.getVersioning()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static org.hl7.fhir.dstu2016may.model.ElementDefinition.TypeRefComponent convertTypeRefComponent(org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent src) throws FHIRException {
|
public static void convertTypeRefComponent(org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent src, List<org.hl7.fhir.dstu2016may.model.ElementDefinition.TypeRefComponent> list) throws FHIRException {
|
||||||
if (src == null || src.isEmpty())
|
if (src == null)
|
||||||
return null;
|
return;
|
||||||
org.hl7.fhir.dstu2016may.model.ElementDefinition.TypeRefComponent tgt = new org.hl7.fhir.dstu2016may.model.ElementDefinition.TypeRefComponent();
|
org.hl7.fhir.dstu2016may.model.ElementDefinition.TypeRefComponent tgt = new org.hl7.fhir.dstu2016may.model.ElementDefinition.TypeRefComponent();
|
||||||
copyElement(src, tgt);
|
copyElement(src, tgt);
|
||||||
tgt.setCode(src.getCode());
|
tgt.setCode(src.getCode());
|
||||||
if (src.hasCode() && "Reference".equals(src.getCode()))
|
list.add(tgt);
|
||||||
tgt.addProfile(src.getTargetProfile());
|
if (src.hasTarget()) {
|
||||||
else
|
for (org.hl7.fhir.r4.model.UriType u : src.getTargetProfile()) {
|
||||||
tgt.addProfile(src.getProfile());
|
tgt.addProfile(u.getValue());
|
||||||
for (org.hl7.fhir.r4.model.Enumeration<org.hl7.fhir.r4.model.ElementDefinition.AggregationMode> t : src.getAggregation())
|
}
|
||||||
tgt.addAggregation(convertAggregationMode(t.getValue()));
|
} else {
|
||||||
tgt.setVersioning(convertReferenceVersionRules(src.getVersioning()));
|
for (org.hl7.fhir.r4.model.UriType u : src.getProfile()) {
|
||||||
return tgt;
|
tgt.addProfile(u.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static org.hl7.fhir.r4.model.ElementDefinition.AggregationMode convertAggregationMode(org.hl7.fhir.dstu2016may.model.ElementDefinition.AggregationMode src) throws FHIRException {
|
private static org.hl7.fhir.r4.model.ElementDefinition.AggregationMode convertAggregationMode(org.hl7.fhir.dstu2016may.model.ElementDefinition.AggregationMode src) throws FHIRException {
|
||||||
|
@ -1576,7 +1605,10 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.setStrength(convertBindingStrength(src.getStrength()));
|
tgt.setStrength(convertBindingStrength(src.getStrength()));
|
||||||
if (src.hasDescription())
|
if (src.hasDescription())
|
||||||
tgt.setDescription(src.getDescription());
|
tgt.setDescription(src.getDescription());
|
||||||
tgt.setValueSet(convertType(src.getValueSet()));
|
if (src.hasValueSet()) {
|
||||||
|
org.hl7.fhir.r4.model.Type vs = convertType(src.getValueSet());
|
||||||
|
tgt.setValueSet(vs instanceof org.hl7.fhir.r4.model.Reference ? new CanonicalType(((org.hl7.fhir.r4.model.Reference) vs).getReference()) : vs);
|
||||||
|
}
|
||||||
return tgt;
|
return tgt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1588,7 +1620,7 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.setStrength(convertBindingStrength(src.getStrength()));
|
tgt.setStrength(convertBindingStrength(src.getStrength()));
|
||||||
if (src.hasDescription())
|
if (src.hasDescription())
|
||||||
tgt.setDescription(src.getDescription());
|
tgt.setDescription(src.getDescription());
|
||||||
tgt.setValueSet(convertType(src.getValueSet()));
|
tgt.setValueSet(src.hasValueSetCanonicalType() ? new org.hl7.fhir.dstu2016may.model.Reference(src.getValueSetCanonicalType().getValue()) : convertType(src.getValueSet()));
|
||||||
return tgt;
|
return tgt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3251,7 +3283,7 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.setSoftware(convertConformanceSoftwareComponent(src.getSoftware()));
|
tgt.setSoftware(convertConformanceSoftwareComponent(src.getSoftware()));
|
||||||
tgt.setImplementation(convertConformanceImplementationComponent(src.getImplementation()));
|
tgt.setImplementation(convertConformanceImplementationComponent(src.getImplementation()));
|
||||||
tgt.setFhirVersion(src.getFhirVersion());
|
tgt.setFhirVersion(src.getFhirVersion());
|
||||||
tgt.setAcceptUnknown(convertUnknownContentCode(src.getAcceptUnknown()));
|
// tgt.setAcceptUnknown(convertUnknownContentCode(src.getAcceptUnknown()));
|
||||||
for (org.hl7.fhir.dstu2016may.model.CodeType t : src.getFormat())
|
for (org.hl7.fhir.dstu2016may.model.CodeType t : src.getFormat())
|
||||||
tgt.addFormat(t.getValue());
|
tgt.addFormat(t.getValue());
|
||||||
// for (org.hl7.fhir.dstu2016may.model.Reference t : src.getProfile())
|
// for (org.hl7.fhir.dstu2016may.model.Reference t : src.getProfile())
|
||||||
|
@ -3265,6 +3297,18 @@ public class VersionConvertor_14_40 {
|
||||||
return tgt;
|
return tgt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static CanonicalType convertReferenceToCanonical(Reference src) throws FHIRException {
|
||||||
|
CanonicalType dst = new CanonicalType(src.getReference());
|
||||||
|
copyElement(src, dst);
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Reference convertCanonicalToReference(CanonicalType src) throws FHIRException {
|
||||||
|
Reference dst = new Reference(src.getValue());
|
||||||
|
copyElement(src, dst);
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
public static org.hl7.fhir.dstu2016may.model.Conformance convertConformance(org.hl7.fhir.r4.model.CapabilityStatement src) throws FHIRException {
|
public static org.hl7.fhir.dstu2016may.model.Conformance convertConformance(org.hl7.fhir.r4.model.CapabilityStatement src) throws FHIRException {
|
||||||
if (src == null || src.isEmpty())
|
if (src == null || src.isEmpty())
|
||||||
return null;
|
return null;
|
||||||
|
@ -3300,13 +3344,13 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.setSoftware(convertConformanceSoftwareComponent(src.getSoftware()));
|
tgt.setSoftware(convertConformanceSoftwareComponent(src.getSoftware()));
|
||||||
tgt.setImplementation(convertConformanceImplementationComponent(src.getImplementation()));
|
tgt.setImplementation(convertConformanceImplementationComponent(src.getImplementation()));
|
||||||
tgt.setFhirVersion(src.getFhirVersion());
|
tgt.setFhirVersion(src.getFhirVersion());
|
||||||
tgt.setAcceptUnknown(convertUnknownContentCode(src.getAcceptUnknown()));
|
// tgt.setAcceptUnknown(convertUnknownContentCode(src.getAcceptUnknown()));
|
||||||
for (org.hl7.fhir.r4.model.CodeType t : src.getFormat())
|
for (org.hl7.fhir.r4.model.CodeType t : src.getFormat())
|
||||||
tgt.addFormat(t.getValue());
|
tgt.addFormat(t.getValue());
|
||||||
for (CapabilityStatementRestComponent r : src.getRest())
|
for (CapabilityStatementRestComponent r : src.getRest())
|
||||||
for (CapabilityStatementRestResourceComponent rr : r.getResource())
|
for (CapabilityStatementRestResourceComponent rr : r.getResource())
|
||||||
for (org.hl7.fhir.r4.model.Reference t : rr.getSupportedProfile())
|
for (org.hl7.fhir.r4.model.CanonicalType t : rr.getSupportedProfile())
|
||||||
tgt.addProfile(convertReference(t));
|
tgt.addProfile(convertCanonicalToReference(t));
|
||||||
for (org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestComponent t : src.getRest())
|
for (org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestComponent t : src.getRest())
|
||||||
tgt.addRest(convertConformanceRestComponent(t));
|
tgt.addRest(convertConformanceRestComponent(t));
|
||||||
for (org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementMessagingComponent t : src.getMessaging())
|
for (org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementMessagingComponent t : src.getMessaging())
|
||||||
|
@ -3337,30 +3381,30 @@ public class VersionConvertor_14_40 {
|
||||||
default: return org.hl7.fhir.dstu2016may.model.Conformance.ConformanceStatementKind.NULL;
|
default: return org.hl7.fhir.dstu2016may.model.Conformance.ConformanceStatementKind.NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//
|
||||||
private static org.hl7.fhir.r4.model.CapabilityStatement.UnknownContentCode convertUnknownContentCode(org.hl7.fhir.dstu2016may.model.Conformance.UnknownContentCode src) throws FHIRException {
|
// private static org.hl7.fhir.r4.model.CapabilityStatement.UnknownContentCode convertUnknownContentCode(org.hl7.fhir.dstu2016may.model.Conformance.UnknownContentCode src) throws FHIRException {
|
||||||
if (src == null)
|
// if (src == null)
|
||||||
return null;
|
// return null;
|
||||||
switch (src) {
|
// switch (src) {
|
||||||
case NO: return org.hl7.fhir.r4.model.CapabilityStatement.UnknownContentCode.NO;
|
// case NO: return org.hl7.fhir.r4.model.CapabilityStatement.UnknownContentCode.NO;
|
||||||
case EXTENSIONS: return org.hl7.fhir.r4.model.CapabilityStatement.UnknownContentCode.EXTENSIONS;
|
// case EXTENSIONS: return org.hl7.fhir.r4.model.CapabilityStatement.UnknownContentCode.EXTENSIONS;
|
||||||
case ELEMENTS: return org.hl7.fhir.r4.model.CapabilityStatement.UnknownContentCode.ELEMENTS;
|
// case ELEMENTS: return org.hl7.fhir.r4.model.CapabilityStatement.UnknownContentCode.ELEMENTS;
|
||||||
case BOTH: return org.hl7.fhir.r4.model.CapabilityStatement.UnknownContentCode.BOTH;
|
// case BOTH: return org.hl7.fhir.r4.model.CapabilityStatement.UnknownContentCode.BOTH;
|
||||||
default: return org.hl7.fhir.r4.model.CapabilityStatement.UnknownContentCode.NULL;
|
// default: return org.hl7.fhir.r4.model.CapabilityStatement.UnknownContentCode.NULL;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private static org.hl7.fhir.dstu2016may.model.Conformance.UnknownContentCode convertUnknownContentCode(org.hl7.fhir.r4.model.CapabilityStatement.UnknownContentCode src) throws FHIRException {
|
// private static org.hl7.fhir.dstu2016may.model.Conformance.UnknownContentCode convertUnknownContentCode(org.hl7.fhir.r4.model.CapabilityStatement.UnknownContentCode src) throws FHIRException {
|
||||||
if (src == null)
|
// if (src == null)
|
||||||
return null;
|
// return null;
|
||||||
switch (src) {
|
// switch (src) {
|
||||||
case NO: return org.hl7.fhir.dstu2016may.model.Conformance.UnknownContentCode.NO;
|
// case NO: return org.hl7.fhir.dstu2016may.model.Conformance.UnknownContentCode.NO;
|
||||||
case EXTENSIONS: return org.hl7.fhir.dstu2016may.model.Conformance.UnknownContentCode.EXTENSIONS;
|
// case EXTENSIONS: return org.hl7.fhir.dstu2016may.model.Conformance.UnknownContentCode.EXTENSIONS;
|
||||||
case ELEMENTS: return org.hl7.fhir.dstu2016may.model.Conformance.UnknownContentCode.ELEMENTS;
|
// case ELEMENTS: return org.hl7.fhir.dstu2016may.model.Conformance.UnknownContentCode.ELEMENTS;
|
||||||
case BOTH: return org.hl7.fhir.dstu2016may.model.Conformance.UnknownContentCode.BOTH;
|
// case BOTH: return org.hl7.fhir.dstu2016may.model.Conformance.UnknownContentCode.BOTH;
|
||||||
default: return org.hl7.fhir.dstu2016may.model.Conformance.UnknownContentCode.NULL;
|
// default: return org.hl7.fhir.dstu2016may.model.Conformance.UnknownContentCode.NULL;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
public static org.hl7.fhir.r4.model.ContactDetail convertConformanceContactComponent(org.hl7.fhir.dstu2016may.model.Conformance.ConformanceContactComponent src) throws FHIRException {
|
public static org.hl7.fhir.r4.model.ContactDetail convertConformanceContactComponent(org.hl7.fhir.dstu2016may.model.Conformance.ConformanceContactComponent src) throws FHIRException {
|
||||||
if (src == null || src.isEmpty())
|
if (src == null || src.isEmpty())
|
||||||
|
@ -3509,8 +3553,6 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.addService(convertCodeableConcept(t));
|
tgt.addService(convertCodeableConcept(t));
|
||||||
if (src.hasDescription())
|
if (src.hasDescription())
|
||||||
tgt.setDescription(src.getDescription());
|
tgt.setDescription(src.getDescription());
|
||||||
for (org.hl7.fhir.dstu2016may.model.Conformance.ConformanceRestSecurityCertificateComponent t : src.getCertificate())
|
|
||||||
tgt.addCertificate(convertConformanceRestSecurityCertificateComponent(t));
|
|
||||||
return tgt;
|
return tgt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3525,32 +3567,6 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.addService(convertCodeableConcept(t));
|
tgt.addService(convertCodeableConcept(t));
|
||||||
if (src.hasDescription())
|
if (src.hasDescription())
|
||||||
tgt.setDescription(src.getDescription());
|
tgt.setDescription(src.getDescription());
|
||||||
for (org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestSecurityCertificateComponent t : src.getCertificate())
|
|
||||||
tgt.addCertificate(convertConformanceRestSecurityCertificateComponent(t));
|
|
||||||
return tgt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestSecurityCertificateComponent convertConformanceRestSecurityCertificateComponent(org.hl7.fhir.dstu2016may.model.Conformance.ConformanceRestSecurityCertificateComponent src) throws FHIRException {
|
|
||||||
if (src == null || src.isEmpty())
|
|
||||||
return null;
|
|
||||||
org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestSecurityCertificateComponent tgt = new org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestSecurityCertificateComponent();
|
|
||||||
copyElement(src, tgt);
|
|
||||||
if (src.hasType())
|
|
||||||
tgt.setType(src.getType());
|
|
||||||
if (src.hasBlob())
|
|
||||||
tgt.setBlob(src.getBlob());
|
|
||||||
return tgt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static org.hl7.fhir.dstu2016may.model.Conformance.ConformanceRestSecurityCertificateComponent convertConformanceRestSecurityCertificateComponent(org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestSecurityCertificateComponent src) throws FHIRException {
|
|
||||||
if (src == null || src.isEmpty())
|
|
||||||
return null;
|
|
||||||
org.hl7.fhir.dstu2016may.model.Conformance.ConformanceRestSecurityCertificateComponent tgt = new org.hl7.fhir.dstu2016may.model.Conformance.ConformanceRestSecurityCertificateComponent();
|
|
||||||
copyElement(src, tgt);
|
|
||||||
if (src.hasType())
|
|
||||||
tgt.setType(src.getType());
|
|
||||||
if (src.hasBlob())
|
|
||||||
tgt.setBlob(src.getBlob());
|
|
||||||
return tgt;
|
return tgt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3560,7 +3576,7 @@ public class VersionConvertor_14_40 {
|
||||||
org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestResourceComponent tgt = new org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestResourceComponent();
|
org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestResourceComponent tgt = new org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestResourceComponent();
|
||||||
copyElement(src, tgt);
|
copyElement(src, tgt);
|
||||||
tgt.setType(src.getType());
|
tgt.setType(src.getType());
|
||||||
tgt.setProfile(convertReference(src.getProfile()));
|
tgt.setProfileElement(convertReferenceToCanonical(src.getProfile()));
|
||||||
for (org.hl7.fhir.dstu2016may.model.Conformance.ResourceInteractionComponent t : src.getInteraction())
|
for (org.hl7.fhir.dstu2016may.model.Conformance.ResourceInteractionComponent t : src.getInteraction())
|
||||||
tgt.addInteraction(convertResourceInteractionComponent(t));
|
tgt.addInteraction(convertResourceInteractionComponent(t));
|
||||||
tgt.setVersioning(convertResourceVersionPolicy(src.getVersioning()));
|
tgt.setVersioning(convertResourceVersionPolicy(src.getVersioning()));
|
||||||
|
@ -3588,7 +3604,7 @@ public class VersionConvertor_14_40 {
|
||||||
org.hl7.fhir.dstu2016may.model.Conformance.ConformanceRestResourceComponent tgt = new org.hl7.fhir.dstu2016may.model.Conformance.ConformanceRestResourceComponent();
|
org.hl7.fhir.dstu2016may.model.Conformance.ConformanceRestResourceComponent tgt = new org.hl7.fhir.dstu2016may.model.Conformance.ConformanceRestResourceComponent();
|
||||||
copyElement(src, tgt);
|
copyElement(src, tgt);
|
||||||
tgt.setType(src.getType());
|
tgt.setType(src.getType());
|
||||||
tgt.setProfile(convertReference(src.getProfile()));
|
tgt.setProfile(convertCanonicalToReference(src.getProfileElement()));
|
||||||
for (org.hl7.fhir.r4.model.CapabilityStatement.ResourceInteractionComponent t : src.getInteraction())
|
for (org.hl7.fhir.r4.model.CapabilityStatement.ResourceInteractionComponent t : src.getInteraction())
|
||||||
tgt.addInteraction(convertResourceInteractionComponent(t));
|
tgt.addInteraction(convertResourceInteractionComponent(t));
|
||||||
tgt.setVersioning(convertResourceVersionPolicy(src.getVersioning()));
|
tgt.setVersioning(convertResourceVersionPolicy(src.getVersioning()));
|
||||||
|
@ -3818,7 +3834,7 @@ public class VersionConvertor_14_40 {
|
||||||
org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestResourceOperationComponent tgt = new org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestResourceOperationComponent();
|
org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestResourceOperationComponent tgt = new org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestResourceOperationComponent();
|
||||||
copyElement(src, tgt);
|
copyElement(src, tgt);
|
||||||
tgt.setName(src.getName());
|
tgt.setName(src.getName());
|
||||||
tgt.setDefinition(convertReference(src.getDefinition()));
|
tgt.setDefinitionElement(convertReferenceToCanonical(src.getDefinition()));
|
||||||
return tgt;
|
return tgt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3828,7 +3844,7 @@ public class VersionConvertor_14_40 {
|
||||||
org.hl7.fhir.dstu2016may.model.Conformance.ConformanceRestOperationComponent tgt = new org.hl7.fhir.dstu2016may.model.Conformance.ConformanceRestOperationComponent();
|
org.hl7.fhir.dstu2016may.model.Conformance.ConformanceRestOperationComponent tgt = new org.hl7.fhir.dstu2016may.model.Conformance.ConformanceRestOperationComponent();
|
||||||
copyElement(src, tgt);
|
copyElement(src, tgt);
|
||||||
tgt.setName(src.getName());
|
tgt.setName(src.getName());
|
||||||
tgt.setDefinition(convertReference(src.getDefinition()));
|
tgt.setDefinition(convertCanonicalToReference(src.getDefinitionElement()));
|
||||||
return tgt;
|
return tgt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3908,7 +3924,7 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.setMode(convertDocumentMode(src.getMode()));
|
tgt.setMode(convertDocumentMode(src.getMode()));
|
||||||
if (src.hasDocumentation())
|
if (src.hasDocumentation())
|
||||||
tgt.setDocumentation(src.getDocumentation());
|
tgt.setDocumentation(src.getDocumentation());
|
||||||
tgt.setProfile(convertReference(src.getProfile()));
|
tgt.setProfileElement(convertReferenceToCanonical(src.getProfile()));
|
||||||
return tgt;
|
return tgt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3920,7 +3936,7 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.setMode(convertDocumentMode(src.getMode()));
|
tgt.setMode(convertDocumentMode(src.getMode()));
|
||||||
if (src.hasDocumentation())
|
if (src.hasDocumentation())
|
||||||
tgt.setDocumentation(src.getDocumentation());
|
tgt.setDocumentation(src.getDocumentation());
|
||||||
tgt.setProfile(convertReference(src.getProfile()));
|
tgt.setProfile(convertCanonicalToReference(src.getProfileElement()));
|
||||||
return tgt;
|
return tgt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4292,7 +4308,7 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.setAcronym(src.getAcronym());
|
tgt.setAcronym(src.getAcronym());
|
||||||
tgt.setSource(convertType(src.getSource()));
|
tgt.setSource(convertType(src.getSource()));
|
||||||
if (src.hasExampleFor())
|
if (src.hasExampleFor())
|
||||||
tgt.setExampleFor(convertReference(src.getExampleFor()));
|
tgt.setExampleForElement(convertReferenceToCanonical(src.getExampleFor()));
|
||||||
return tgt;
|
return tgt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4310,7 +4326,7 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.setAcronym(src.getAcronym());
|
tgt.setAcronym(src.getAcronym());
|
||||||
tgt.setSource(convertType(src.getSource()));
|
tgt.setSource(convertType(src.getSource()));
|
||||||
if (src.hasExampleFor())
|
if (src.hasExampleFor())
|
||||||
tgt.setExampleFor(convertReference(src.getExampleFor()));
|
tgt.setExampleFor(convertCanonicalToReference(src.getExampleForElement()));
|
||||||
return tgt;
|
return tgt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4320,7 +4336,7 @@ public class VersionConvertor_14_40 {
|
||||||
org.hl7.fhir.r4.model.ImplementationGuide.ImplementationGuideGlobalComponent tgt = new org.hl7.fhir.r4.model.ImplementationGuide.ImplementationGuideGlobalComponent();
|
org.hl7.fhir.r4.model.ImplementationGuide.ImplementationGuideGlobalComponent tgt = new org.hl7.fhir.r4.model.ImplementationGuide.ImplementationGuideGlobalComponent();
|
||||||
copyElement(src, tgt);
|
copyElement(src, tgt);
|
||||||
tgt.setType(src.getType());
|
tgt.setType(src.getType());
|
||||||
tgt.setProfile(convertReference(src.getProfile()));
|
tgt.setProfileElement(convertReferenceToCanonical(src.getProfile()));
|
||||||
return tgt;
|
return tgt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4330,7 +4346,7 @@ public class VersionConvertor_14_40 {
|
||||||
org.hl7.fhir.dstu2016may.model.ImplementationGuide.ImplementationGuideGlobalComponent tgt = new org.hl7.fhir.dstu2016may.model.ImplementationGuide.ImplementationGuideGlobalComponent();
|
org.hl7.fhir.dstu2016may.model.ImplementationGuide.ImplementationGuideGlobalComponent tgt = new org.hl7.fhir.dstu2016may.model.ImplementationGuide.ImplementationGuideGlobalComponent();
|
||||||
copyElement(src, tgt);
|
copyElement(src, tgt);
|
||||||
tgt.setType(src.getType());
|
tgt.setType(src.getType());
|
||||||
tgt.setProfile(convertReference(src.getProfile()));
|
tgt.setProfile(convertCanonicalToReference(src.getProfileElement()));
|
||||||
return tgt;
|
return tgt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4594,7 +4610,7 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.setCode(src.getCode());
|
tgt.setCode(src.getCode());
|
||||||
if (src.hasComment())
|
if (src.hasComment())
|
||||||
tgt.setComment(src.getComment());
|
tgt.setComment(src.getComment());
|
||||||
tgt.setBase(convertReference(src.getBase()));
|
tgt.setBaseElement(convertReferenceToCanonical(src.getBase()));
|
||||||
tgt.setSystem(src.getSystem());
|
tgt.setSystem(src.getSystem());
|
||||||
for (org.hl7.fhir.dstu2016may.model.CodeType t : src.getType())
|
for (org.hl7.fhir.dstu2016may.model.CodeType t : src.getType())
|
||||||
tgt.addResource(t.getValue());
|
tgt.addResource(t.getValue());
|
||||||
|
@ -4639,7 +4655,7 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.setCode(src.getCode());
|
tgt.setCode(src.getCode());
|
||||||
if (src.hasComment())
|
if (src.hasComment())
|
||||||
tgt.setComment(src.getComment());
|
tgt.setComment(src.getComment());
|
||||||
tgt.setBase(convertReference(src.getBase()));
|
tgt.setBase(convertCanonicalToReference(src.getBaseElement()));
|
||||||
tgt.setSystem(src.getSystem());
|
tgt.setSystem(src.getSystem());
|
||||||
if (src.getType())
|
if (src.getType())
|
||||||
for (org.hl7.fhir.r4.model.CodeType t : src.getResource())
|
for (org.hl7.fhir.r4.model.CodeType t : src.getResource())
|
||||||
|
@ -5054,10 +5070,10 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.setReadOnly(src.getReadOnly());
|
tgt.setReadOnly(src.getReadOnly());
|
||||||
if (src.hasMaxLength())
|
if (src.hasMaxLength())
|
||||||
tgt.setMaxLength(src.getMaxLength());
|
tgt.setMaxLength(src.getMaxLength());
|
||||||
tgt.setOptions(convertReference(src.getOptions()));
|
tgt.setOptionsElement(convertReferenceToCanonical(src.getOptions()));
|
||||||
for (org.hl7.fhir.dstu2016may.model.Questionnaire.QuestionnaireItemOptionComponent t : src.getOption())
|
for (org.hl7.fhir.dstu2016may.model.Questionnaire.QuestionnaireItemOptionComponent t : src.getOption())
|
||||||
tgt.addOption(convertQuestionnaireItemOptionComponent(t));
|
tgt.addOption(convertQuestionnaireItemOptionComponent(t));
|
||||||
tgt.setInitial(convertType(src.getInitial()));
|
tgt.addInitial().setValue(convertType(src.getInitial()));
|
||||||
for (org.hl7.fhir.dstu2016may.model.Questionnaire.QuestionnaireItemComponent t : src.getItem())
|
for (org.hl7.fhir.dstu2016may.model.Questionnaire.QuestionnaireItemComponent t : src.getItem())
|
||||||
tgt.addItem(convertQuestionnaireItemComponent(t));
|
tgt.addItem(convertQuestionnaireItemComponent(t));
|
||||||
return tgt;
|
return tgt;
|
||||||
|
@ -5087,10 +5103,11 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.setReadOnly(src.getReadOnly());
|
tgt.setReadOnly(src.getReadOnly());
|
||||||
if (src.hasMaxLength())
|
if (src.hasMaxLength())
|
||||||
tgt.setMaxLength(src.getMaxLength());
|
tgt.setMaxLength(src.getMaxLength());
|
||||||
tgt.setOptions(convertReference(src.getOptions()));
|
tgt.setOptions(convertCanonicalToReference(src.getOptionsElement()));
|
||||||
for (org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemOptionComponent t : src.getOption())
|
for (org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemOptionComponent t : src.getOption())
|
||||||
tgt.addOption(convertQuestionnaireItemOptionComponent(t));
|
tgt.addOption(convertQuestionnaireItemOptionComponent(t));
|
||||||
tgt.setInitial(convertType(src.getInitial()));
|
if (src.hasInitial())
|
||||||
|
tgt.setInitial(convertType(src.getInitialFirstRep().getValue()));
|
||||||
for (org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemComponent t : src.getItem())
|
for (org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemComponent t : src.getItem())
|
||||||
tgt.addItem(convertQuestionnaireItemComponent(t));
|
tgt.addItem(convertQuestionnaireItemComponent(t));
|
||||||
return tgt;
|
return tgt;
|
||||||
|
@ -5153,8 +5170,10 @@ public class VersionConvertor_14_40 {
|
||||||
org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemEnableWhenComponent tgt = new org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemEnableWhenComponent();
|
org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemEnableWhenComponent tgt = new org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemEnableWhenComponent();
|
||||||
copyElement(src, tgt);
|
copyElement(src, tgt);
|
||||||
tgt.setQuestion(src.getQuestion());
|
tgt.setQuestion(src.getQuestion());
|
||||||
if (src.hasAnswered())
|
if (src.hasAnswered()) {
|
||||||
tgt.setHasAnswer(src.getAnswered());
|
tgt.setOperator(QuestionnaireItemOperator.EXISTS);
|
||||||
|
tgt.setAnswer(convertType(src.getAnsweredElement()));
|
||||||
|
}
|
||||||
tgt.setAnswer(convertType(src.getAnswer()));
|
tgt.setAnswer(convertType(src.getAnswer()));
|
||||||
return tgt;
|
return tgt;
|
||||||
}
|
}
|
||||||
|
@ -5165,9 +5184,10 @@ public class VersionConvertor_14_40 {
|
||||||
org.hl7.fhir.dstu2016may.model.Questionnaire.QuestionnaireItemEnableWhenComponent tgt = new org.hl7.fhir.dstu2016may.model.Questionnaire.QuestionnaireItemEnableWhenComponent();
|
org.hl7.fhir.dstu2016may.model.Questionnaire.QuestionnaireItemEnableWhenComponent tgt = new org.hl7.fhir.dstu2016may.model.Questionnaire.QuestionnaireItemEnableWhenComponent();
|
||||||
copyElement(src, tgt);
|
copyElement(src, tgt);
|
||||||
tgt.setQuestion(src.getQuestion());
|
tgt.setQuestion(src.getQuestion());
|
||||||
if (src.hasHasAnswer())
|
if (src.hasOperator() && src.getOperator() == QuestionnaireItemOperator.EXISTS)
|
||||||
tgt.setAnswered(src.getHasAnswer());
|
tgt.setAnswered(src.getAnswerBooleanType().getValue());
|
||||||
tgt.setAnswer(convertType(src.getAnswer()));
|
else
|
||||||
|
tgt.setAnswer(convertType(src.getAnswer()));
|
||||||
return tgt;
|
return tgt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5195,7 +5215,7 @@ public class VersionConvertor_14_40 {
|
||||||
org.hl7.fhir.r4.model.QuestionnaireResponse tgt = new org.hl7.fhir.r4.model.QuestionnaireResponse();
|
org.hl7.fhir.r4.model.QuestionnaireResponse tgt = new org.hl7.fhir.r4.model.QuestionnaireResponse();
|
||||||
copyDomainResource(src, tgt);
|
copyDomainResource(src, tgt);
|
||||||
tgt.setIdentifier(convertIdentifier(src.getIdentifier()));
|
tgt.setIdentifier(convertIdentifier(src.getIdentifier()));
|
||||||
tgt.setQuestionnaire(convertReference(src.getQuestionnaire()));
|
tgt.setQuestionnaireElement(convertReferenceToCanonical(src.getQuestionnaire()));
|
||||||
tgt.setStatus(convertQuestionnaireResponseStatus(src.getStatus()));
|
tgt.setStatus(convertQuestionnaireResponseStatus(src.getStatus()));
|
||||||
tgt.setSubject(convertReference(src.getSubject()));
|
tgt.setSubject(convertReference(src.getSubject()));
|
||||||
tgt.setContext(convertReference(src.getEncounter()));
|
tgt.setContext(convertReference(src.getEncounter()));
|
||||||
|
@ -5214,7 +5234,7 @@ public class VersionConvertor_14_40 {
|
||||||
org.hl7.fhir.dstu2016may.model.QuestionnaireResponse tgt = new org.hl7.fhir.dstu2016may.model.QuestionnaireResponse();
|
org.hl7.fhir.dstu2016may.model.QuestionnaireResponse tgt = new org.hl7.fhir.dstu2016may.model.QuestionnaireResponse();
|
||||||
copyDomainResource(src, tgt);
|
copyDomainResource(src, tgt);
|
||||||
tgt.setIdentifier(convertIdentifier(src.getIdentifier()));
|
tgt.setIdentifier(convertIdentifier(src.getIdentifier()));
|
||||||
tgt.setQuestionnaire(convertReference(src.getQuestionnaire()));
|
tgt.setQuestionnaire(convertCanonicalToReference(src.getQuestionnaireElement()));
|
||||||
tgt.setStatus(convertQuestionnaireResponseStatus(src.getStatus()));
|
tgt.setStatus(convertQuestionnaireResponseStatus(src.getStatus()));
|
||||||
tgt.setSubject(convertReference(src.getSubject()));
|
tgt.setSubject(convertReference(src.getSubject()));
|
||||||
tgt.setEncounter(convertReference(src.getContext()));
|
tgt.setEncounter(convertReference(src.getContext()));
|
||||||
|
@ -5472,9 +5492,11 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.addMapping(convertStructureDefinitionMappingComponent(t));
|
tgt.addMapping(convertStructureDefinitionMappingComponent(t));
|
||||||
tgt.setKind(convertStructureDefinitionKind(src.getKind()));
|
tgt.setKind(convertStructureDefinitionKind(src.getKind()));
|
||||||
tgt.setAbstract(src.getAbstract());
|
tgt.setAbstract(src.getAbstract());
|
||||||
tgt.setContextType(convertExtensionContext(src.getContextType()));
|
for (org.hl7.fhir.dstu2016may.model.StringType t : src.getContext()) {
|
||||||
for (org.hl7.fhir.dstu2016may.model.StringType t : src.getContext())
|
org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionContextComponent ec = tgt.addContext();
|
||||||
tgt.addContext(t.getValue());
|
ec.setType(convertExtensionContext(src.getContextType()));
|
||||||
|
ec.setExpression(t.getValue());
|
||||||
|
}
|
||||||
if (src.getDerivation() == org.hl7.fhir.dstu2016may.model.StructureDefinition.TypeDerivationRule.CONSTRAINT)
|
if (src.getDerivation() == org.hl7.fhir.dstu2016may.model.StructureDefinition.TypeDerivationRule.CONSTRAINT)
|
||||||
tgt.setType(src.getBaseType());
|
tgt.setType(src.getBaseType());
|
||||||
else
|
else
|
||||||
|
@ -5490,6 +5512,13 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.setDifferential(convertStructureDefinitionDifferentialComponent(src.getDifferential()));
|
tgt.setDifferential(convertStructureDefinitionDifferentialComponent(src.getDifferential()));
|
||||||
tgt.getDifferential().getElementFirstRep().getType().clear();
|
tgt.getDifferential().getElementFirstRep().getType().clear();
|
||||||
}
|
}
|
||||||
|
if (tgt.getDerivation() == TypeDerivationRule.SPECIALIZATION) {
|
||||||
|
for (ElementDefinition ed : tgt.getSnapshot().getElement()) {
|
||||||
|
if (!ed.hasBase()) {
|
||||||
|
ed.getBase().setPath(ed.getPath()).setMin(ed.getMin()).setMax(ed.getMax());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return tgt;
|
return tgt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5535,9 +5564,11 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.addMapping(convertStructureDefinitionMappingComponent(t));
|
tgt.addMapping(convertStructureDefinitionMappingComponent(t));
|
||||||
tgt.setKind(convertStructureDefinitionKind(src.getKind()));
|
tgt.setKind(convertStructureDefinitionKind(src.getKind()));
|
||||||
tgt.setAbstract(src.getAbstract());
|
tgt.setAbstract(src.getAbstract());
|
||||||
tgt.setContextType(convertExtensionContext(src.getContextType()));
|
for (org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionContextComponent t : src.getContext()) {
|
||||||
for (org.hl7.fhir.r4.model.StringType t : src.getContext())
|
if (!tgt.hasContextType())
|
||||||
tgt.addContext(t.getValue());
|
tgt.setContextType(convertExtensionContext(t.getType()));
|
||||||
|
tgt.addContext(t.getExpression());
|
||||||
|
}
|
||||||
if (src.hasBaseDefinition())
|
if (src.hasBaseDefinition())
|
||||||
tgt.setBaseDefinition(src.getBaseDefinition());
|
tgt.setBaseDefinition(src.getBaseDefinition());
|
||||||
if (src.hasType() && src.getDerivation() == org.hl7.fhir.r4.model.StructureDefinition.TypeDerivationRule.CONSTRAINT)
|
if (src.hasType() && src.getDerivation() == org.hl7.fhir.r4.model.StructureDefinition.TypeDerivationRule.CONSTRAINT)
|
||||||
|
@ -5572,23 +5603,23 @@ public class VersionConvertor_14_40 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static org.hl7.fhir.r4.model.StructureDefinition.ExtensionContext convertExtensionContext(org.hl7.fhir.dstu2016may.model.StructureDefinition.ExtensionContext src) throws FHIRException {
|
private static org.hl7.fhir.r4.model.StructureDefinition.ExtensionContextType convertExtensionContext(org.hl7.fhir.dstu2016may.model.StructureDefinition.ExtensionContext src) throws FHIRException {
|
||||||
if (src == null)
|
if (src == null)
|
||||||
return null;
|
return null;
|
||||||
switch (src) {
|
switch (src) {
|
||||||
case RESOURCE: return org.hl7.fhir.r4.model.StructureDefinition.ExtensionContext.RESOURCE;
|
case RESOURCE: return org.hl7.fhir.r4.model.StructureDefinition.ExtensionContextType.FHIRPATH;
|
||||||
case DATATYPE: return org.hl7.fhir.r4.model.StructureDefinition.ExtensionContext.DATATYPE;
|
case DATATYPE: return org.hl7.fhir.r4.model.StructureDefinition.ExtensionContextType.ELEMENT;
|
||||||
case EXTENSION: return org.hl7.fhir.r4.model.StructureDefinition.ExtensionContext.EXTENSION;
|
case EXTENSION: return org.hl7.fhir.r4.model.StructureDefinition.ExtensionContextType.EXTENSION;
|
||||||
default: return org.hl7.fhir.r4.model.StructureDefinition.ExtensionContext.NULL;
|
default: return org.hl7.fhir.r4.model.StructureDefinition.ExtensionContextType.NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static org.hl7.fhir.dstu2016may.model.StructureDefinition.ExtensionContext convertExtensionContext(org.hl7.fhir.r4.model.StructureDefinition.ExtensionContext src) throws FHIRException {
|
private static org.hl7.fhir.dstu2016may.model.StructureDefinition.ExtensionContext convertExtensionContext(org.hl7.fhir.r4.model.StructureDefinition.ExtensionContextType src) throws FHIRException {
|
||||||
if (src == null)
|
if (src == null)
|
||||||
return null;
|
return null;
|
||||||
switch (src) {
|
switch (src) {
|
||||||
case RESOURCE: return org.hl7.fhir.dstu2016may.model.StructureDefinition.ExtensionContext.RESOURCE;
|
case FHIRPATH: return org.hl7.fhir.dstu2016may.model.StructureDefinition.ExtensionContext.RESOURCE;
|
||||||
case DATATYPE: return org.hl7.fhir.dstu2016may.model.StructureDefinition.ExtensionContext.DATATYPE;
|
case ELEMENT: return org.hl7.fhir.dstu2016may.model.StructureDefinition.ExtensionContext.DATATYPE;
|
||||||
case EXTENSION: return org.hl7.fhir.dstu2016may.model.StructureDefinition.ExtensionContext.EXTENSION;
|
case EXTENSION: return org.hl7.fhir.dstu2016may.model.StructureDefinition.ExtensionContext.EXTENSION;
|
||||||
default: return org.hl7.fhir.dstu2016may.model.StructureDefinition.ExtensionContext.NULL;
|
default: return org.hl7.fhir.dstu2016may.model.StructureDefinition.ExtensionContext.NULL;
|
||||||
}
|
}
|
||||||
|
@ -6186,6 +6217,8 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.setLabel(src.getLabel());
|
tgt.setLabel(src.getLabel());
|
||||||
if (src.hasDescription())
|
if (src.hasDescription())
|
||||||
tgt.setDescription(src.getDescription());
|
tgt.setDescription(src.getDescription());
|
||||||
|
tgt.setAccept(convertContentType(src.getAccept()));
|
||||||
|
tgt.setContentType(convertContentType(src.getContentType()));
|
||||||
if (src.hasDestination())
|
if (src.hasDestination())
|
||||||
tgt.setDestination(src.getDestination());
|
tgt.setDestination(src.getDestination());
|
||||||
if (src.hasEncodeRequestUrl())
|
if (src.hasEncodeRequestUrl())
|
||||||
|
@ -6218,6 +6251,8 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.setLabel(src.getLabel());
|
tgt.setLabel(src.getLabel());
|
||||||
if (src.hasDescription())
|
if (src.hasDescription())
|
||||||
tgt.setDescription(src.getDescription());
|
tgt.setDescription(src.getDescription());
|
||||||
|
tgt.setAccept(convertContentType(src.getAccept()));
|
||||||
|
tgt.setContentType(convertContentType(src.getContentType()));
|
||||||
if (src.hasDestination())
|
if (src.hasDestination())
|
||||||
tgt.setDestination(src.getDestination());
|
tgt.setDestination(src.getDestination());
|
||||||
if (src.hasEncodeRequestUrl())
|
if (src.hasEncodeRequestUrl())
|
||||||
|
@ -6239,6 +6274,24 @@ public class VersionConvertor_14_40 {
|
||||||
return tgt;
|
return tgt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String convertContentType(org.hl7.fhir.dstu2016may.model.TestScript.ContentType src) throws FHIRException {
|
||||||
|
if (src == null)
|
||||||
|
return null;
|
||||||
|
switch (src) {
|
||||||
|
case XML: return "application/fhir+xml";
|
||||||
|
case JSON: return "application/fhir+json";
|
||||||
|
default: return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static org.hl7.fhir.dstu2016may.model.TestScript.ContentType convertContentType(String src) throws FHIRException {
|
||||||
|
if (src == null)
|
||||||
|
return null;
|
||||||
|
if (src.contains("xml")) return org.hl7.fhir.dstu2016may.model.TestScript.ContentType.XML;
|
||||||
|
if (src.contains("json")) return org.hl7.fhir.dstu2016may.model.TestScript.ContentType.JSON;
|
||||||
|
return org.hl7.fhir.dstu2016may.model.TestScript.ContentType.NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static org.hl7.fhir.r4.model.TestScript.SetupActionOperationRequestHeaderComponent convertSetupActionOperationRequestHeaderComponent(org.hl7.fhir.dstu2016may.model.TestScript.SetupActionOperationRequestHeaderComponent src) throws FHIRException {
|
public static org.hl7.fhir.r4.model.TestScript.SetupActionOperationRequestHeaderComponent convertSetupActionOperationRequestHeaderComponent(org.hl7.fhir.dstu2016may.model.TestScript.SetupActionOperationRequestHeaderComponent src) throws FHIRException {
|
||||||
if (src == null || src.isEmpty())
|
if (src == null || src.isEmpty())
|
||||||
|
@ -6274,6 +6327,7 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.setCompareToSourceId(src.getCompareToSourceId());
|
tgt.setCompareToSourceId(src.getCompareToSourceId());
|
||||||
if (src.hasCompareToSourcePath())
|
if (src.hasCompareToSourcePath())
|
||||||
tgt.setCompareToSourcePath(src.getCompareToSourcePath());
|
tgt.setCompareToSourcePath(src.getCompareToSourcePath());
|
||||||
|
tgt.setContentType(convertContentType(src.getContentType()));
|
||||||
if (src.hasHeaderField())
|
if (src.hasHeaderField())
|
||||||
tgt.setHeaderField(src.getHeaderField());
|
tgt.setHeaderField(src.getHeaderField());
|
||||||
if (src.hasMinimumId())
|
if (src.hasMinimumId())
|
||||||
|
@ -6315,6 +6369,7 @@ public class VersionConvertor_14_40 {
|
||||||
tgt.setCompareToSourceId(src.getCompareToSourceId());
|
tgt.setCompareToSourceId(src.getCompareToSourceId());
|
||||||
if (src.hasCompareToSourcePath())
|
if (src.hasCompareToSourcePath())
|
||||||
tgt.setCompareToSourcePath(src.getCompareToSourcePath());
|
tgt.setCompareToSourcePath(src.getCompareToSourcePath());
|
||||||
|
tgt.setContentType(convertContentType(src.getContentType()));
|
||||||
if (src.hasHeaderField())
|
if (src.hasHeaderField())
|
||||||
tgt.setHeaderField(src.getHeaderField());
|
tgt.setHeaderField(src.getHeaderField());
|
||||||
if (src.hasMinimumId())
|
if (src.hasMinimumId())
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,487 +0,0 @@
|
||||||
package org.hl7.fhir.dstu2.utils;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* #%L
|
|
||||||
* HAPI FHIR - Converter
|
|
||||||
* %%
|
|
||||||
* Copyright (C) 2014 - 2018 University Health Network
|
|
||||||
* %%
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
* #L%
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright (c) 2011+, HL7, Inc
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
* Neither the name of HL7 nor the names of its contributors may be used to
|
|
||||||
endorse or promote products derived from this software without specific
|
|
||||||
prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
||||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
||||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
||||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.hl7.fhir.instance.model.BooleanType;
|
|
||||||
import org.hl7.fhir.instance.model.CodeType;
|
|
||||||
import org.hl7.fhir.instance.model.CodeableConcept;
|
|
||||||
import org.hl7.fhir.instance.model.Coding;
|
|
||||||
import org.hl7.fhir.instance.model.DataElement;
|
|
||||||
import org.hl7.fhir.instance.model.DomainResource;
|
|
||||||
import org.hl7.fhir.instance.model.Element;
|
|
||||||
import org.hl7.fhir.instance.model.ElementDefinition;
|
|
||||||
import org.hl7.fhir.instance.model.Extension;
|
|
||||||
import org.hl7.fhir.instance.model.ExtensionHelper;
|
|
||||||
import org.hl7.fhir.instance.model.Factory;
|
|
||||||
import org.hl7.fhir.instance.model.Identifier;
|
|
||||||
import org.hl7.fhir.instance.model.IntegerType;
|
|
||||||
import org.hl7.fhir.instance.model.MarkdownType;
|
|
||||||
import org.hl7.fhir.instance.model.PrimitiveType;
|
|
||||||
import org.hl7.fhir.instance.model.Questionnaire.GroupComponent;
|
|
||||||
import org.hl7.fhir.instance.model.Questionnaire.QuestionComponent;
|
|
||||||
import org.hl7.fhir.instance.model.Reference;
|
|
||||||
import org.hl7.fhir.instance.model.StringType;
|
|
||||||
import org.hl7.fhir.instance.model.Type;
|
|
||||||
import org.hl7.fhir.instance.model.UriType;
|
|
||||||
import org.hl7.fhir.instance.model.ValueSet;
|
|
||||||
import org.hl7.fhir.instance.model.ValueSet.ConceptDefinitionComponent;
|
|
||||||
import org.hl7.fhir.instance.model.ValueSet.ValueSetCodeSystemComponent;
|
|
||||||
import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
|
|
||||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
|
||||||
import org.hl7.fhir.utilities.Utilities;
|
|
||||||
|
|
||||||
|
|
||||||
public class ToolingExtensions {
|
|
||||||
|
|
||||||
// validated
|
|
||||||
public static final String EXT_SUBSUMES = "http://hl7.org/fhir/StructureDefinition/valueset-subsumes";
|
|
||||||
private static final String EXT_OID = "http://hl7.org/fhir/StructureDefinition/valueset-oid";
|
|
||||||
public static final String EXT_DEPRECATED = "http://hl7.org/fhir/StructureDefinition/valueset-deprecated";
|
|
||||||
public static final String EXT_DEFINITION = "http://hl7.org/fhir/StructureDefinition/valueset-definition";
|
|
||||||
public static final String EXT_COMMENT = "http://hl7.org/fhir/StructureDefinition/valueset-comments";
|
|
||||||
private static final String EXT_IDENTIFIER = "http://hl7.org/fhir/StructureDefinition/identifier";
|
|
||||||
private static final String EXT_TRANSLATION = "http://hl7.org/fhir/StructureDefinition/translation";
|
|
||||||
public static final String EXT_ISSUE_SOURCE = "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-source";
|
|
||||||
public static final String EXT_DISPLAY_HINT = "http://hl7.org/fhir/StructureDefinition/structuredefinition-display-hint";
|
|
||||||
public static final String EXT_REPLACED_BY = "http://hl7.org/fhir/StructureDefinition/valueset-replacedby";
|
|
||||||
public static final String EXT_JSON_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-json-type";
|
|
||||||
public static final String EXT_XML_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-xml-type";
|
|
||||||
public static final String EXT_REGEX = "http://hl7.org/fhir/StructureDefinition/structuredefinition-regex";
|
|
||||||
public static final String EXT_EXPRESSION = "http://hl7.org/fhir/StructureDefinition/structuredefinition-expression";
|
|
||||||
public static final String EXT_SEARCH_EXPRESSION = "http://hl7.org/fhir/StructureDefinition/searchparameter-expression";
|
|
||||||
|
|
||||||
// unregistered?
|
|
||||||
|
|
||||||
public static final String EXT_FLYOVER = "http://hl7.org/fhir/Profile/questionnaire-extensions#flyover";
|
|
||||||
private static final String EXT_QTYPE = "http://www.healthintersections.com.au/fhir/Profile/metadata#type";
|
|
||||||
private static final String EXT_QREF = "http://www.healthintersections.com.au/fhir/Profile/metadata#reference";
|
|
||||||
private static final String EXTENSION_FILTER_ONLY = "http://www.healthintersections.com.au/fhir/Profile/metadata#expandNeedsFilter";
|
|
||||||
private static final String EXT_TYPE = "http://www.healthintersections.com.au/fhir/Profile/metadata#type";
|
|
||||||
private static final String EXT_REFERENCE = "http://www.healthintersections.com.au/fhir/Profile/metadata#reference";
|
|
||||||
private static final String EXT_ALLOWABLE_UNITS = "http://hl7.org/fhir/StructureDefinition/elementdefinition-allowedUnits";
|
|
||||||
public static final String EXT_CIMI_REFERENCE = "http://hl7.org/fhir/StructureDefinition/cimi-reference";
|
|
||||||
public static final String EXT_UNCLOSED = "http://hl7.org/fhir/StructureDefinition/valueset-unclosed";
|
|
||||||
public static final String EXT_FMM_LEVEL = "http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm";
|
|
||||||
|
|
||||||
|
|
||||||
// specific extension helpers
|
|
||||||
|
|
||||||
public static Extension makeIssueSource(Source source) {
|
|
||||||
Extension ex = new Extension();
|
|
||||||
// todo: write this up and get it published with the pack (and handle the redirect?)
|
|
||||||
ex.setUrl(ToolingExtensions.EXT_ISSUE_SOURCE);
|
|
||||||
CodeType c = new CodeType();
|
|
||||||
c.setValue(source.toString());
|
|
||||||
ex.setValue(c);
|
|
||||||
return ex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean hasExtension(DomainResource de, String url) {
|
|
||||||
return getExtension(de, url) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean hasExtension(Element e, String url) {
|
|
||||||
return getExtension(e, url) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addStringExtension(DomainResource dr, String url, String content) {
|
|
||||||
if (!Utilities.noString(content)) {
|
|
||||||
Extension ex = getExtension(dr, url);
|
|
||||||
if (ex != null)
|
|
||||||
ex.setValue(new StringType(content));
|
|
||||||
else
|
|
||||||
dr.getExtension().add(Factory.newExtension(url, new StringType(content), true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addStringExtension(Element e, String url, String content) {
|
|
||||||
if (!Utilities.noString(content)) {
|
|
||||||
Extension ex = getExtension(e, url);
|
|
||||||
if (ex != null)
|
|
||||||
ex.setValue(new StringType(content));
|
|
||||||
else
|
|
||||||
e.getExtension().add(Factory.newExtension(url, new StringType(content), true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addIntegerExtension(DomainResource dr, String url, int value) {
|
|
||||||
Extension ex = getExtension(dr, url);
|
|
||||||
if (ex != null)
|
|
||||||
ex.setValue(new IntegerType(value));
|
|
||||||
else
|
|
||||||
dr.getExtension().add(Factory.newExtension(url, new IntegerType(value), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addComment(Element nc, String comment) {
|
|
||||||
if (!Utilities.noString(comment))
|
|
||||||
nc.getExtension().add(Factory.newExtension(EXT_COMMENT, Factory.newString_(comment), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void markDeprecated(Element nc) {
|
|
||||||
setDeprecated(nc);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addSubsumes(ConceptDefinitionComponent nc, String code) {
|
|
||||||
nc.getModifierExtension().add(Factory.newExtension(EXT_SUBSUMES, Factory.newCode(code), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addDefinition(Element nc, String definition) {
|
|
||||||
if (!Utilities.noString(definition))
|
|
||||||
nc.getExtension().add(Factory.newExtension(EXT_DEFINITION, Factory.newString_(definition), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addDisplayHint(Element def, String hint) {
|
|
||||||
if (!Utilities.noString(hint))
|
|
||||||
def.getExtension().add(Factory.newExtension(EXT_DISPLAY_HINT, Factory.newString_(hint), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getDisplayHint(Element def) {
|
|
||||||
return readStringExtension(def, EXT_DISPLAY_HINT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String readStringExtension(Element c, String uri) {
|
|
||||||
Extension ex = ExtensionHelper.getExtension(c, uri);
|
|
||||||
if (ex == null)
|
|
||||||
return null;
|
|
||||||
if (ex.getValue() instanceof UriType)
|
|
||||||
return ((UriType) ex.getValue()).getValue();
|
|
||||||
if (!(ex.getValue() instanceof StringType))
|
|
||||||
return null;
|
|
||||||
return ((StringType) ex.getValue()).getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String readStringExtension(DomainResource c, String uri) {
|
|
||||||
Extension ex = getExtension(c, uri);
|
|
||||||
if (ex == null)
|
|
||||||
return null;
|
|
||||||
if ((ex.getValue() instanceof StringType))
|
|
||||||
return ((StringType) ex.getValue()).getValue();
|
|
||||||
if ((ex.getValue() instanceof UriType))
|
|
||||||
return ((UriType) ex.getValue()).getValue();
|
|
||||||
if ((ex.getValue() instanceof MarkdownType))
|
|
||||||
return ((MarkdownType) ex.getValue()).getValue();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static PrimitiveType<Type> readPrimitiveExtension(DomainResource c, String uri) {
|
|
||||||
Extension ex = getExtension(c, uri);
|
|
||||||
if (ex == null)
|
|
||||||
return null;
|
|
||||||
return (PrimitiveType<Type>) ex.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean findStringExtension(Element c, String uri) {
|
|
||||||
Extension ex = ExtensionHelper.getExtension(c, uri);
|
|
||||||
if (ex == null)
|
|
||||||
return false;
|
|
||||||
if (!(ex.getValue() instanceof StringType))
|
|
||||||
return false;
|
|
||||||
return !Utilities.noString(((StringType) ex.getValue()).getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Boolean readBooleanExtension(Element c, String uri) {
|
|
||||||
Extension ex = ExtensionHelper.getExtension(c, uri);
|
|
||||||
if (ex == null)
|
|
||||||
return null;
|
|
||||||
if (!(ex.getValue() instanceof BooleanType))
|
|
||||||
return null;
|
|
||||||
return ((BooleanType) ex.getValue()).getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean findBooleanExtension(Element c, String uri) {
|
|
||||||
Extension ex = ExtensionHelper.getExtension(c, uri);
|
|
||||||
if (ex == null)
|
|
||||||
return false;
|
|
||||||
if (!(ex.getValue() instanceof BooleanType))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getComment(ConceptDefinitionComponent c) {
|
|
||||||
return readStringExtension(c, EXT_COMMENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Boolean getDeprecated(Element c) {
|
|
||||||
return readBooleanExtension(c, EXT_DEPRECATED);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean hasComment(ConceptDefinitionComponent c) {
|
|
||||||
return findStringExtension(c, EXT_COMMENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean hasDeprecated(Element c) {
|
|
||||||
return findBooleanExtension(c, EXT_DEPRECATED);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<CodeType> getSubsumes(ConceptDefinitionComponent c) {
|
|
||||||
List<CodeType> res = new ArrayList<CodeType>();
|
|
||||||
|
|
||||||
for (Extension e : c.getExtension()) {
|
|
||||||
if (EXT_SUBSUMES.equals(e.getUrl()))
|
|
||||||
res.add((CodeType) e.getValue());
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addFlyOver(GroupComponent group, String text) {
|
|
||||||
if (!Utilities.noString(text))
|
|
||||||
group.getExtension().add(Factory.newExtension(EXT_FLYOVER, Factory.newString_(text), true));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setQuestionType(GroupComponent group, String text) {
|
|
||||||
if (!Utilities.noString(text))
|
|
||||||
group.getExtension().add(Factory.newExtension(EXT_QTYPE, Factory.newString_(text), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setQuestionReference(GroupComponent group, String text) {
|
|
||||||
if (!Utilities.noString(text))
|
|
||||||
group.getExtension().add(Factory.newExtension(EXT_QREF, Factory.newString_(text), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addFlyOver(Element element, String text) {
|
|
||||||
element.getExtension().add(Factory.newExtension(EXT_FLYOVER, Factory.newString_(text), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addFilterOnly(Reference element, boolean value) {
|
|
||||||
element.getExtension().add(Factory.newExtension(EXTENSION_FILTER_ONLY, Factory.newBoolean(value), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addType(GroupComponent group, String value) {
|
|
||||||
group.getExtension().add(Factory.newExtension(EXT_TYPE, Factory.newString_(value), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addReference(QuestionComponent group, String value) {
|
|
||||||
group.getExtension().add(Factory.newExtension(EXT_REFERENCE, Factory.newString_(value), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addIdentifier(Element element, Identifier value) {
|
|
||||||
element.getExtension().add(Factory.newExtension(EXT_IDENTIFIER, value, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param name the identity of the extension of interest
|
|
||||||
* @return The extension, if on this element, else null
|
|
||||||
*/
|
|
||||||
public static Extension getExtension(DomainResource resource, String name) {
|
|
||||||
if (name == null)
|
|
||||||
return null;
|
|
||||||
if (!resource.hasExtension())
|
|
||||||
return null;
|
|
||||||
for (Extension e : resource.getExtension()) {
|
|
||||||
if (name.equals(e.getUrl()))
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Extension getExtension(Element el, String name) {
|
|
||||||
if (name == null)
|
|
||||||
return null;
|
|
||||||
if (!el.hasExtension())
|
|
||||||
return null;
|
|
||||||
for (Extension e : el.getExtension()) {
|
|
||||||
if (name.equals(e.getUrl()))
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setStringExtension(DomainResource resource, String uri, String value) {
|
|
||||||
Extension ext = getExtension(resource, uri);
|
|
||||||
if (ext != null)
|
|
||||||
ext.setValue(new StringType(value));
|
|
||||||
else
|
|
||||||
resource.getExtension().add(new Extension(new UriType(uri)).setValue(new StringType(value)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getOID(ValueSetCodeSystemComponent define) {
|
|
||||||
return readStringExtension(define, EXT_OID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getOID(ValueSet vs) {
|
|
||||||
return readStringExtension(vs, EXT_OID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setOID(ValueSetCodeSystemComponent define, String oid) throws FHIRFormatError, URISyntaxException {
|
|
||||||
if (!oid.startsWith("urn:oid:"))
|
|
||||||
throw new FHIRFormatError("Error in OID format");
|
|
||||||
if (oid.startsWith("urn:oid:urn:oid:"))
|
|
||||||
throw new FHIRFormatError("Error in OID format");
|
|
||||||
define.getExtension().add(Factory.newExtension(EXT_OID, Factory.newUri(oid), false));
|
|
||||||
}
|
|
||||||
public static void setOID(ValueSet vs, String oid) throws FHIRFormatError, URISyntaxException {
|
|
||||||
if (!oid.startsWith("urn:oid:"))
|
|
||||||
throw new FHIRFormatError("Error in OID format");
|
|
||||||
if (oid.startsWith("urn:oid:urn:oid:"))
|
|
||||||
throw new FHIRFormatError("Error in OID format");
|
|
||||||
vs.getExtension().add(Factory.newExtension(EXT_OID, Factory.newUri(oid), false));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean hasLanguageTranslation(Element element, String lang) {
|
|
||||||
for (Extension e : element.getExtension()) {
|
|
||||||
if (e.getUrl().equals(EXT_TRANSLATION)) {
|
|
||||||
Extension e1 = ExtensionHelper.getExtension(e, "lang");
|
|
||||||
|
|
||||||
if (e1 != null && e1.getValue() instanceof CodeType && ((CodeType) e.getValue()).getValue().equals(lang))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getLanguageTranslation(Element element, String lang) {
|
|
||||||
for (Extension e : element.getExtension()) {
|
|
||||||
if (e.getUrl().equals(EXT_TRANSLATION)) {
|
|
||||||
Extension e1 = ExtensionHelper.getExtension(e, "lang");
|
|
||||||
|
|
||||||
if (e1 != null && e1.getValue() instanceof CodeType && ((CodeType) e.getValue()).getValue().equals(lang)) {
|
|
||||||
e1 = ExtensionHelper.getExtension(e, "content");
|
|
||||||
return ((StringType) e.getValue()).getValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addLanguageTranslation(Element element, String lang, String value) {
|
|
||||||
Extension extension = new Extension().setUrl(EXT_TRANSLATION);
|
|
||||||
extension.addExtension().setUrl("lang").setValue(new StringType(lang));
|
|
||||||
extension.addExtension().setUrl("content").setValue(new StringType(value));
|
|
||||||
element.getExtension().add(extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Type getAllowedUnits(ElementDefinition eld) {
|
|
||||||
for (Extension e : eld.getExtension())
|
|
||||||
if (e.getUrl().equals(EXT_ALLOWABLE_UNITS))
|
|
||||||
return e.getValue();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setAllowableUnits(ElementDefinition eld, CodeableConcept cc) {
|
|
||||||
for (Extension e : eld.getExtension())
|
|
||||||
if (e.getUrl().equals(EXT_ALLOWABLE_UNITS)) {
|
|
||||||
e.setValue(cc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
eld.getExtension().add(new Extension().setUrl(EXT_ALLOWABLE_UNITS).setValue(cc));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Extension> getExtensions(Element element, String url) {
|
|
||||||
List<Extension> results = new ArrayList<Extension>();
|
|
||||||
for (Extension ex : element.getExtension())
|
|
||||||
if (ex.getUrl().equals(url))
|
|
||||||
results.add(ex);
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Extension> getExtensions(DomainResource resource, String url) {
|
|
||||||
List<Extension> results = new ArrayList<Extension>();
|
|
||||||
for (Extension ex : resource.getExtension())
|
|
||||||
if (ex.getUrl().equals(url))
|
|
||||||
results.add(ex);
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addDEReference(DataElement de, String value) {
|
|
||||||
for (Extension e : de.getExtension())
|
|
||||||
if (e.getUrl().equals(EXT_CIMI_REFERENCE)) {
|
|
||||||
e.setValue(new UriType(value));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
de.getExtension().add(new Extension().setUrl(EXT_CIMI_REFERENCE).setValue(new UriType(value)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setDeprecated(Element nc) {
|
|
||||||
for (Extension e : nc.getExtension())
|
|
||||||
if (e.getUrl().equals(EXT_DEPRECATED)) {
|
|
||||||
e.setValue(new BooleanType(true));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
nc.getExtension().add(new Extension().setUrl(EXT_DEPRECATED).setValue(new BooleanType(true)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setExtension(Element focus, String url, Coding c) {
|
|
||||||
for (Extension e : focus.getExtension())
|
|
||||||
if (e.getUrl().equals(url)) {
|
|
||||||
e.setValue(c);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
focus.getExtension().add(new Extension().setUrl(url).setValue(c));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void removeExtension(DomainResource focus, String url) {
|
|
||||||
Iterator<Extension> i = focus.getExtension().iterator();
|
|
||||||
while (i.hasNext()) {
|
|
||||||
Extension e = i.next(); // must be called before you can call i.remove()
|
|
||||||
if (e.getUrl().equals(url)) {
|
|
||||||
i.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void removeExtension(Element focus, String url) {
|
|
||||||
Iterator<Extension> i = focus.getExtension().iterator();
|
|
||||||
while (i.hasNext()) {
|
|
||||||
Extension e = i.next(); // must be called before you can call i.remove()
|
|
||||||
if (e.getUrl().equals(url)) {
|
|
||||||
i.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
package ca.uhn.hapi.converters.server;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Search;
|
||||||
|
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||||
|
import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
|
||||||
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
|
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||||
|
import ca.uhn.fhir.util.PortUtil;
|
||||||
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
import ca.uhn.fhir.util.UrlUtil;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
|
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.servlet.ServletHandler;
|
||||||
|
import org.eclipse.jetty.servlet.ServletHolder;
|
||||||
|
import org.hl7.fhir.dstu3.model.HumanName;
|
||||||
|
import org.hl7.fhir.dstu3.model.Patient;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
public class VersionedApiConverterInterceptorR4Test {
|
||||||
|
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(VersionedApiConverterInterceptorR4Test.class);
|
||||||
|
private static CloseableHttpClient ourClient;
|
||||||
|
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||||
|
private static int ourPort;
|
||||||
|
|
||||||
|
private static Server ourServer;
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchNormal() throws Exception {
|
||||||
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
|
||||||
|
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
assertThat(responseContent, containsString("\"family\": \"FAMILY\""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchConvertToR2() throws Exception {
|
||||||
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
|
||||||
|
httpGet.addHeader("Accept", "application/fhir+json; fhirVersion=1.0");
|
||||||
|
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
assertThat(responseContent, containsString("\"family\": ["));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchConvertToR2ByFormatParam() throws Exception {
|
||||||
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=" + UrlUtil.escapeUrlParam("application/fhir+json; fhirVersion=1.0"));
|
||||||
|
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
assertThat(responseContent, containsString("\"family\": ["));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClassClearContext() throws Exception {
|
||||||
|
ourServer.stop();
|
||||||
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void beforeClass() throws Exception {
|
||||||
|
ourPort = PortUtil.findFreePort();
|
||||||
|
ourServer = new Server(ourPort);
|
||||||
|
|
||||||
|
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
|
||||||
|
|
||||||
|
ServletHandler proxyHandler = new ServletHandler();
|
||||||
|
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||||
|
servlet.setDefaultResponseEncoding(EncodingEnum.JSON);
|
||||||
|
servlet.setDefaultPrettyPrint(true);
|
||||||
|
servlet.registerInterceptor(new VersionedApiConverterInterceptor());
|
||||||
|
|
||||||
|
servlet.setResourceProviders(patientProvider);
|
||||||
|
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||||
|
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||||
|
ourServer.setHandler(proxyHandler);
|
||||||
|
ourServer.start();
|
||||||
|
|
||||||
|
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||||
|
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||||
|
builder.setConnectionManager(connectionManager);
|
||||||
|
ourClient = builder.build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends IBaseResource> getResourceType() {
|
||||||
|
return Patient.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
@Search()
|
||||||
|
public List search() {
|
||||||
|
ArrayList<Patient> retVal = new ArrayList<>();
|
||||||
|
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.getIdElement().setValue("Patient/A");
|
||||||
|
patient.addName(new HumanName().setFamily("FAMILY"));
|
||||||
|
retVal.add(patient);
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
<configuration>
|
||||||
|
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||||
|
<level>INFO</level>
|
||||||
|
</filter>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%file:%line] %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<logger name="org.springframework.web.socket.handler.ExceptionWebSocketHandlerDecorator" additivity="false" level="info">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
<logger name="ca.uhn.fhir.jpa.dao.FhirResourceDaoSubscriptionDstu2" additivity="false" level="info">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
<logger name="org.eclipse.jetty.websocket" additivity="false" level="info">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
<logger name="org.eclipse" additivity="false" level="error">
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
<logger name="ca.uhn.fhir.rest.client" additivity="false" level="info">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
<logger name="ca.uhn.fhir.jpa.dao" additivity="false" level="info">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
<!-- Set to 'trace' to enable SQL logging -->
|
||||||
|
<logger name="org.hibernate.SQL" additivity="false" level="info">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</logger>
|
||||||
|
<!-- Set to 'trace' to enable SQL Value logging -->
|
||||||
|
<logger name="org.hibernate.type" additivity="false" level="info">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
<root level="info">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</root>
|
||||||
|
|
||||||
|
</configuration>
|
|
@ -23,7 +23,7 @@ package ca.uhn.fhir.igpacks.parser;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
|
|
|
@ -20,31 +20,31 @@ package ca.uhn.fhir.jaxrs.client;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||||
|
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||||
|
import ca.uhn.fhir.rest.client.api.IHttpResponse;
|
||||||
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
|
|
||||||
|
import javax.ws.rs.client.Entity;
|
||||||
|
import javax.ws.rs.client.Invocation;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.ws.rs.client.Entity;
|
|
||||||
import javax.ws.rs.client.Invocation;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
|
||||||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
|
||||||
import ca.uhn.fhir.rest.client.api.IHttpResponse;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Http Request based on JaxRs. This is an adapter around the class
|
* A Http Request based on JaxRs. This is an adapter around the class
|
||||||
* {@link javax.ws.rs.client.Invocation Invocation}
|
* {@link javax.ws.rs.client.Invocation Invocation}
|
||||||
*
|
*
|
||||||
* @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
|
* @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
|
||||||
*/
|
*/
|
||||||
public class JaxRsHttpRequest implements IHttpRequest {
|
public class JaxRsHttpRequest implements IHttpRequest {
|
||||||
|
|
||||||
|
private final Map<String, List<String>> myHeaders = new HashMap<String, List<String>>();
|
||||||
private Invocation.Builder myRequest;
|
private Invocation.Builder myRequest;
|
||||||
private RequestTypeEnum myRequestType;
|
private RequestTypeEnum myRequestType;
|
||||||
private Entity<?> myEntity;
|
private Entity<?> myEntity;
|
||||||
private final Map<String, List<String>> myHeaders = new HashMap<String, List<String>>();
|
|
||||||
|
|
||||||
public JaxRsHttpRequest(Invocation.Builder theRequest, RequestTypeEnum theRequestType, Entity<?> theEntity) {
|
public JaxRsHttpRequest(Invocation.Builder theRequest, RequestTypeEnum theRequestType, Entity<?> theEntity) {
|
||||||
this.myRequest = theRequest;
|
this.myRequest = theRequest;
|
||||||
|
@ -61,24 +61,22 @@ public class JaxRsHttpRequest implements IHttpRequest {
|
||||||
getRequest().header(theName, theValue);
|
getRequest().header(theName, theValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Get the Request
|
public IHttpResponse execute() {
|
||||||
* @return the Request
|
StopWatch responseStopWatch = new StopWatch();
|
||||||
*/
|
Invocation invocation = getRequest().build(getRequestType().name(), getEntity());
|
||||||
public Invocation.Builder getRequest() {
|
Response response = invocation.invoke();
|
||||||
return myRequest;
|
return new JaxRsHttpResponse(response, responseStopWatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Get the Request Type
|
public Map<String, List<String>> getAllHeaders() {
|
||||||
* @return the request type
|
return this.myHeaders;
|
||||||
*/
|
|
||||||
public RequestTypeEnum getRequestType() {
|
|
||||||
return myRequestType == null ? RequestTypeEnum.GET : myRequestType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the Entity
|
* Get the Entity
|
||||||
|
*
|
||||||
* @return the entity
|
* @return the entity
|
||||||
*/
|
*/
|
||||||
public Entity<?> getEntity() {
|
public Entity<?> getEntity() {
|
||||||
|
@ -86,15 +84,17 @@ public class JaxRsHttpRequest implements IHttpRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IHttpResponse execute() {
|
public String getHttpVerbName() {
|
||||||
Invocation invocation = getRequest().build(getRequestType().name(), getEntity());
|
return myRequestType.name();
|
||||||
Response response = invocation.invoke();
|
|
||||||
return new JaxRsHttpResponse(response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public Map<String, List<String>> getAllHeaders() {
|
* Get the Request
|
||||||
return this.myHeaders;
|
*
|
||||||
|
* @return the Request
|
||||||
|
*/
|
||||||
|
public Invocation.Builder getRequest() {
|
||||||
|
return myRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -103,14 +103,18 @@ public class JaxRsHttpRequest implements IHttpRequest {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Request Type
|
||||||
|
*
|
||||||
|
* @return the request type
|
||||||
|
*/
|
||||||
|
public RequestTypeEnum getRequestType() {
|
||||||
|
return myRequestType == null ? RequestTypeEnum.GET : myRequestType;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUri() {
|
public String getUri() {
|
||||||
return ""; // TODO: can we get this from somewhere?
|
return ""; // TODO: can we get this from somewhere?
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getHttpVerbName() {
|
|
||||||
return myRequestType.name();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
@ -34,7 +33,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
import ca.uhn.fhir.rest.client.impl.BaseHttpResponse;
|
||||||
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
|
|
||||||
import ca.uhn.fhir.rest.client.api.IHttpResponse;
|
import ca.uhn.fhir.rest.client.api.IHttpResponse;
|
||||||
|
|
||||||
|
@ -42,12 +42,13 @@ import ca.uhn.fhir.rest.client.api.IHttpResponse;
|
||||||
* A Http Response based on JaxRs. This is an adapter around the class {@link javax.ws.rs.core.Response Response}
|
* A Http Response based on JaxRs. This is an adapter around the class {@link javax.ws.rs.core.Response Response}
|
||||||
* @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
|
* @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
|
||||||
*/
|
*/
|
||||||
public class JaxRsHttpResponse implements IHttpResponse {
|
public class JaxRsHttpResponse extends BaseHttpResponse implements IHttpResponse {
|
||||||
|
|
||||||
private boolean myBufferedEntity = false;
|
private boolean myBufferedEntity = false;
|
||||||
private final Response myResponse;
|
private final Response myResponse;
|
||||||
|
|
||||||
public JaxRsHttpResponse(Response theResponse) {
|
public JaxRsHttpResponse(Response theResponse, StopWatch theResponseStopWatch) {
|
||||||
|
super(theResponseStopWatch);
|
||||||
this.myResponse = theResponse;
|
this.myResponse = theResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ public class JaxRsResponse extends RestfulResponse<JaxRsRequest> {
|
||||||
StringWriter writer = new StringWriter();
|
StringWriter writer = new StringWriter();
|
||||||
if (outcome != null) {
|
if (outcome != null) {
|
||||||
FhirContext fhirContext = getRequestDetails().getServer().getFhirContext();
|
FhirContext fhirContext = getRequestDetails().getServer().getFhirContext();
|
||||||
IParser parser = RestfulServerUtils.getNewParser(fhirContext, getRequestDetails());
|
IParser parser = RestfulServerUtils.getNewParser(fhirContext, fhirContext.getVersion().getVersion(), getRequestDetails());
|
||||||
outcome.execute(parser, writer);
|
outcome.execute(parser, writer);
|
||||||
}
|
}
|
||||||
return sendWriterResponse(operationStatus, getParserType(), null, writer);
|
return sendWriterResponse(operationStatus, getParserType(), null, writer);
|
||||||
|
|
|
@ -114,19 +114,19 @@ public class JaxRsResponseDstu3Test {
|
||||||
boolean allowPrefer = true;
|
boolean allowPrefer = true;
|
||||||
String resourceName = "Patient";
|
String resourceName = "Patient";
|
||||||
MethodOutcome methodOutcome = new MethodOutcome(theId);
|
MethodOutcome methodOutcome = new MethodOutcome(theId);
|
||||||
response.getRequestDetails().getParameters().put(Constants.PARAM_FORMAT, new String[]{Constants.CT_XML});
|
response.getRequestDetails().addParameter(Constants.PARAM_FORMAT, new String[]{Constants.CT_XML});
|
||||||
boolean addContentLocationHeader = true;
|
boolean addContentLocationHeader = true;
|
||||||
boolean respondGzip = true;
|
boolean respondGzip = true;
|
||||||
Response result = (Response) RestfulServerUtils.streamResponseAsResource(request.getServer(), createPatient(), theSummaryMode, 200, addContentLocationHeader, respondGzip, this.request);
|
Response result = (Response) RestfulServerUtils.streamResponseAsResource(request.getServer(), createPatient(), theSummaryMode, 200, addContentLocationHeader, respondGzip, this.request);
|
||||||
assertEquals(200, result.getStatus());
|
assertEquals(200, result.getStatus());
|
||||||
assertEquals("application/xml+fhir; charset=UTF-8", result.getHeaderString(Constants.HEADER_CONTENT_TYPE));
|
assertEquals("application/fhir+xml; charset=UTF-8", result.getHeaderString(Constants.HEADER_CONTENT_TYPE));
|
||||||
assertTrue(result.getEntity().toString().contains("<Patient"));
|
assertTrue(result.getEntity().toString().contains("<Patient"));
|
||||||
assertTrue(result.getEntity().toString().contains("15"));
|
assertTrue(result.getEntity().toString().contains("15"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoOutcomeXml() throws IOException {
|
public void testNoOutcomeXml() throws IOException {
|
||||||
response.getRequestDetails().getParameters().put(Constants.PARAM_FORMAT, new String[]{Constants.CT_XML});
|
response.getRequestDetails().addParameter(Constants.PARAM_FORMAT, new String[]{Constants.CT_XML});
|
||||||
boolean addContentLocationHeader = true;
|
boolean addContentLocationHeader = true;
|
||||||
boolean respondGzip = true;
|
boolean respondGzip = true;
|
||||||
Response result = (Response) RestfulServerUtils.streamResponseAsResource(request.getServer(), null, theSummaryMode, 204, addContentLocationHeader, respondGzip, this.request);
|
Response result = (Response) RestfulServerUtils.streamResponseAsResource(request.getServer(), null, theSummaryMode, 204, addContentLocationHeader, respondGzip, this.request);
|
||||||
|
|
|
@ -88,7 +88,7 @@ public class JaxRsResponseTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReturnResponseAsXml() throws IOException {
|
public void testReturnResponseAsXml() throws IOException {
|
||||||
response.getRequestDetails().getParameters().put(Constants.PARAM_FORMAT, new String[] { Constants.CT_XML });
|
response.getRequestDetails().addParameter(Constants.PARAM_FORMAT, new String[] { Constants.CT_XML });
|
||||||
boolean addContentLocationHeader = true;
|
boolean addContentLocationHeader = true;
|
||||||
boolean respondGzip = true;
|
boolean respondGzip = true;
|
||||||
Response result = (Response) RestfulServerUtils.streamResponseAsResource(request.getServer(), createPatient(), theSummaryMode, 200, addContentLocationHeader, respondGzip, this.request);
|
Response result = (Response) RestfulServerUtils.streamResponseAsResource(request.getServer(), createPatient(), theSummaryMode, 200, addContentLocationHeader, respondGzip, this.request);
|
||||||
|
@ -100,7 +100,7 @@ public class JaxRsResponseTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoOutcomeXml() throws IOException {
|
public void testNoOutcomeXml() throws IOException {
|
||||||
response.getRequestDetails().getParameters().put(Constants.PARAM_FORMAT, new String[] { Constants.CT_XML });
|
response.getRequestDetails().addParameter(Constants.PARAM_FORMAT, new String[] { Constants.CT_XML });
|
||||||
boolean addContentLocationHeader = true;
|
boolean addContentLocationHeader = true;
|
||||||
boolean respondGzip = true;
|
boolean respondGzip = true;
|
||||||
Response result = (Response) RestfulServerUtils.streamResponseAsResource(request.getServer(), createPatient(), theSummaryMode, 200, addContentLocationHeader, respondGzip, this.request);
|
Response result = (Response) RestfulServerUtils.streamResponseAsResource(request.getServer(), createPatient(), theSummaryMode, 200, addContentLocationHeader, respondGzip, this.request);
|
||||||
|
|
|
@ -550,6 +550,27 @@
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
|
<dependencies>
|
||||||
|
<!--
|
||||||
|
These have been added as explicit dependencies
|
||||||
|
as JDK9 no longer includes them by default
|
||||||
|
-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.xml.bind</groupId>
|
||||||
|
<artifactId>jaxb-api</artifactId>
|
||||||
|
<version>${jaxb_api_version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.xml.bind</groupId>
|
||||||
|
<artifactId>jaxb-core</artifactId>
|
||||||
|
<version>${jaxb_core_version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.xml.bind</groupId>
|
||||||
|
<artifactId>jaxb-impl</artifactId>
|
||||||
|
<version>${jaxb_core_version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.jacoco</groupId>
|
<groupId>org.jacoco</groupId>
|
||||||
|
|
|
@ -49,6 +49,8 @@ import javax.annotation.Resource;
|
||||||
@EnableJpaRepositories(basePackages = "ca.uhn.fhir.jpa.dao.data")
|
@EnableJpaRepositories(basePackages = "ca.uhn.fhir.jpa.dao.data")
|
||||||
public class BaseConfig implements SchedulingConfigurer {
|
public class BaseConfig implements SchedulingConfigurer {
|
||||||
|
|
||||||
|
public static final String TASK_EXECUTOR_NAME = "hapiJpaTaskExecutor";
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
protected Environment myEnv;
|
protected Environment myEnv;
|
||||||
@Resource
|
@Resource
|
||||||
|
@ -87,18 +89,6 @@ public class BaseConfig implements SchedulingConfigurer {
|
||||||
return new StaleSearchDeletingSvcImpl();
|
return new StaleSearchDeletingSvcImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
@Lazy
|
|
||||||
public SubscriptionRestHookInterceptor subscriptionRestHookInterceptor() {
|
|
||||||
return new SubscriptionRestHookInterceptor();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@Lazy
|
|
||||||
public SubscriptionWebsocketInterceptor subscriptionWebsocketInterceptor() {
|
|
||||||
return new SubscriptionWebsocketInterceptor();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Note: If you're going to use this, you need to provide a bean
|
* Note: If you're going to use this, you need to provide a bean
|
||||||
* of type {@link ca.uhn.fhir.jpa.subscription.email.IEmailSender}
|
* of type {@link ca.uhn.fhir.jpa.subscription.email.IEmailSender}
|
||||||
|
@ -111,6 +101,18 @@ public class BaseConfig implements SchedulingConfigurer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@Lazy
|
||||||
|
public SubscriptionRestHookInterceptor subscriptionRestHookInterceptor() {
|
||||||
|
return new SubscriptionRestHookInterceptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Lazy
|
||||||
|
public SubscriptionWebsocketInterceptor subscriptionWebsocketInterceptor() {
|
||||||
|
return new SubscriptionWebsocketInterceptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean(name=TASK_EXECUTOR_NAME)
|
||||||
public TaskScheduler taskScheduler() {
|
public TaskScheduler taskScheduler() {
|
||||||
ConcurrentTaskScheduler retVal = new ConcurrentTaskScheduler();
|
ConcurrentTaskScheduler retVal = new ConcurrentTaskScheduler();
|
||||||
retVal.setConcurrentExecutor(scheduledExecutorService().getObject());
|
retVal.setConcurrentExecutor(scheduledExecutorService().getObject());
|
||||||
|
|
|
@ -18,7 +18,7 @@ import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu3;
|
||||||
import ca.uhn.fhir.validation.IValidatorModule;
|
import ca.uhn.fhir.validation.IValidatorModule;
|
||||||
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
||||||
import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator;
|
import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator;
|
||||||
import org.hl7.fhir.dstu3.utils.IResourceValidator.BestPracticeWarningLevel;
|
import org.hl7.fhir.r4.utils.IResourceValidator;
|
||||||
import org.springframework.beans.factory.annotation.Autowire;
|
import org.springframework.beans.factory.annotation.Autowire;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
@ -66,7 +66,7 @@ public class BaseDstu3Config extends BaseConfig {
|
||||||
@Lazy
|
@Lazy
|
||||||
public IValidatorModule instanceValidatorDstu3() {
|
public IValidatorModule instanceValidatorDstu3() {
|
||||||
FhirInstanceValidator val = new FhirInstanceValidator();
|
FhirInstanceValidator val = new FhirInstanceValidator();
|
||||||
val.setBestPracticeWarningLevel(BestPracticeWarningLevel.Warning);
|
val.setBestPracticeWarningLevel(IResourceValidator.BestPracticeWarningLevel.Warning);
|
||||||
val.setValidationSupport(validationSupportChainDstu3());
|
val.setValidationSupport(validationSupportChainDstu3());
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,7 @@ import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
import ca.uhn.fhir.util.*;
|
import ca.uhn.fhir.util.*;
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Charsets;
|
import com.google.common.base.Charsets;
|
||||||
import com.google.common.collect.ArrayListMultimap;
|
import com.google.common.collect.ArrayListMultimap;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
@ -60,9 +61,14 @@ import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.apache.http.NameValuePair;
|
import org.apache.http.NameValuePair;
|
||||||
import org.apache.http.client.utils.URLEncodedUtils;
|
import org.apache.http.client.utils.URLEncodedUtils;
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.internal.SessionImpl;
|
||||||
import org.hl7.fhir.instance.model.api.*;
|
import org.hl7.fhir.instance.model.api.*;
|
||||||
import org.hl7.fhir.r4.model.BaseResource;
|
import org.hl7.fhir.r4.model.BaseResource;
|
||||||
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
|
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
|
||||||
|
import org.hl7.fhir.r4.model.CanonicalType;
|
||||||
|
import org.hl7.fhir.r4.model.IdType;
|
||||||
|
import org.hl7.fhir.r4.model.Reference;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
|
||||||
|
@ -75,18 +81,17 @@ import javax.xml.stream.events.Characters;
|
||||||
import javax.xml.stream.events.XMLEvent;
|
import javax.xml.stream.events.XMLEvent;
|
||||||
import java.io.CharArrayWriter;
|
import java.io.CharArrayWriter;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.io.Writer;
|
|
||||||
import java.nio.CharBuffer;
|
|
||||||
import java.text.Normalizer;
|
import java.text.Normalizer;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.*;
|
import static org.apache.commons.lang3.StringUtils.*;
|
||||||
|
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
|
|
||||||
public static final long INDEX_STATUS_INDEXED = Long.valueOf(1L);
|
public static final long INDEX_STATUS_INDEXED = 1L;
|
||||||
public static final long INDEX_STATUS_INDEXING_FAILED = Long.valueOf(2L);
|
public static final long INDEX_STATUS_INDEXING_FAILED = 2L;
|
||||||
public static final String NS_JPA_PROFILE = "https://github.com/jamesagnew/hapi-fhir/ns/jpa/profile";
|
public static final String NS_JPA_PROFILE = "https://github.com/jamesagnew/hapi-fhir/ns/jpa/profile";
|
||||||
public static final String OO_SEVERITY_ERROR = "error";
|
public static final String OO_SEVERITY_ERROR = "error";
|
||||||
public static final String OO_SEVERITY_INFO = "information";
|
public static final String OO_SEVERITY_INFO = "information";
|
||||||
|
@ -104,6 +109,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiFhirDao.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiFhirDao.class);
|
||||||
private static final Map<FhirVersionEnum, FhirContext> ourRetrievalContexts = new HashMap<FhirVersionEnum, FhirContext>();
|
private static final Map<FhirVersionEnum, FhirContext> ourRetrievalContexts = new HashMap<FhirVersionEnum, FhirContext>();
|
||||||
private static final String PROCESSING_SUB_REQUEST = "BaseHapiFhirDao.processingSubRequest";
|
private static final String PROCESSING_SUB_REQUEST = "BaseHapiFhirDao.processingSubRequest";
|
||||||
|
private static boolean ourValidationDisabledForUnitTest;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
Map<String, Class<? extends IQueryParameterType>> resourceMetaParams = new HashMap<String, Class<? extends IQueryParameterType>>();
|
Map<String, Class<? extends IQueryParameterType>> resourceMetaParams = new HashMap<String, Class<? extends IQueryParameterType>>();
|
||||||
|
@ -310,6 +316,10 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
nextObject = ((IBaseExtension<?, ?>) nextObject).getValue();
|
nextObject = ((IBaseExtension<?, ?>) nextObject).getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nextObject instanceof CanonicalType) {
|
||||||
|
nextObject = new Reference(((CanonicalType) nextObject).getValueAsString());
|
||||||
|
}
|
||||||
|
|
||||||
IIdType nextId;
|
IIdType nextId;
|
||||||
if (nextObject instanceof IBaseReference) {
|
if (nextObject instanceof IBaseReference) {
|
||||||
IBaseReference nextValue = (IBaseReference) nextObject;
|
IBaseReference nextValue = (IBaseReference) nextObject;
|
||||||
|
@ -379,7 +389,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
} else {
|
} else {
|
||||||
ResourceLink resourceLink = new ResourceLink(nextPathAndRef.getPath(), theEntity, nextId, theUpdateTime);
|
ResourceLink resourceLink = new ResourceLink(nextPathAndRef.getPath(), theEntity, nextId, theUpdateTime);
|
||||||
if (theLinks.add(resourceLink)) {
|
if (theLinks.add(resourceLink)) {
|
||||||
ourLog.info("Indexing remote resource reference URL: {}", nextId);
|
ourLog.debug("Indexing remote resource reference URL: {}", nextId);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -417,7 +427,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
IBaseResource newResource = missingResourceDef.newInstance();
|
IBaseResource newResource = missingResourceDef.newInstance();
|
||||||
newResource.setId(resName + "/" + id);
|
newResource.setId(resName + "/" + id);
|
||||||
IFhirResourceDao<IBaseResource> placeholderResourceDao = (IFhirResourceDao<IBaseResource>) getDao(newResource.getClass());
|
IFhirResourceDao<IBaseResource> placeholderResourceDao = (IFhirResourceDao<IBaseResource>) getDao(newResource.getClass());
|
||||||
ourLog.info("Automatically creating empty placeholder resource: {}", newResource.getIdElement().getValue());
|
ourLog.debug("Automatically creating empty placeholder resource: {}", newResource.getIdElement().getValue());
|
||||||
valueOf = placeholderResourceDao.update(newResource).getEntity().getId();
|
valueOf = placeholderResourceDao.update(newResource).getEntity().getId();
|
||||||
} else {
|
} else {
|
||||||
throw new InvalidRequestException("Resource " + resName + "/" + id + " not found, specified in path: " + nextPathsUnsplit);
|
throw new InvalidRequestException("Resource " + resName + "/" + id + " not found, specified in path: " + nextPathsUnsplit);
|
||||||
|
@ -632,6 +642,16 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void flushJpaSession() {
|
||||||
|
SessionImpl session = (SessionImpl) myEntityManager.unwrap(Session.class);
|
||||||
|
int insertionCount = session.getActionQueue().numberOfInsertions();
|
||||||
|
int updateCount = session.getActionQueue().numberOfUpdates();
|
||||||
|
|
||||||
|
StopWatch sw = new StopWatch();
|
||||||
|
myEntityManager.flush();
|
||||||
|
ourLog.debug("Session flush took {}ms for {} inserts and {} updates", sw.getMillis(), insertionCount, updateCount);
|
||||||
|
}
|
||||||
|
|
||||||
private Set<TagDefinition> getAllTagDefinitions(ResourceTable theEntity) {
|
private Set<TagDefinition> getAllTagDefinitions(ResourceTable theEntity) {
|
||||||
HashSet<TagDefinition> retVal = Sets.newHashSet();
|
HashSet<TagDefinition> retVal = Sets.newHashSet();
|
||||||
for (ResourceTag next : theEntity.getTags()) {
|
for (ResourceTag next : theEntity.getTags()) {
|
||||||
|
@ -673,7 +693,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <R extends IBaseResource> IFhirResourceDao<R> getDao(Class<R> theType) {
|
public <R extends IBaseResource> IFhirResourceDao<R> getDao(Class<R> theType) {
|
||||||
if (myResourceTypeToDao == null) {
|
if (myResourceTypeToDao == null) {
|
||||||
Map<Class<? extends IBaseResource>, IFhirResourceDao<?>> theResourceTypeToDao = new HashMap<Class<? extends IBaseResource>, IFhirResourceDao<?>>();
|
Map<Class<? extends IBaseResource>, IFhirResourceDao<?>> theResourceTypeToDao = new HashMap<>();
|
||||||
for (IFhirResourceDao<?> next : myResourceDaos) {
|
for (IFhirResourceDao<?> next : myResourceDaos) {
|
||||||
theResourceTypeToDao.put(next.getResourceType(), next);
|
theResourceTypeToDao.put(next.getResourceType(), next);
|
||||||
}
|
}
|
||||||
|
@ -1213,6 +1233,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
retVal.removeAll(theToRemove);
|
retVal.removeAll(theToRemove);
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setUpdatedTime(Collection<? extends BaseResourceIndexedSearchParam> theParams, Date theUpdateTime) {
|
private void setUpdatedTime(Collection<? extends BaseResourceIndexedSearchParam> theParams, Date theUpdateTime) {
|
||||||
for (BaseResourceIndexedSearchParam nextSearchParam : theParams) {
|
for (BaseResourceIndexedSearchParam nextSearchParam : theParams) {
|
||||||
nextSearchParam.setUpdated(theUpdateTime);
|
nextSearchParam.setUpdated(theUpdateTime);
|
||||||
|
@ -1377,7 +1398,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
*/
|
*/
|
||||||
if (theResource != null) {
|
if (theResource != null) {
|
||||||
if (thePerformIndexing) {
|
if (thePerformIndexing) {
|
||||||
validateResourceForStorage((T) theResource, theEntity);
|
if (!ourValidationDisabledForUnitTest) {
|
||||||
|
validateResourceForStorage((T) theResource, theEntity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
String resourceType = myContext.getResourceDefinition(theResource).getName();
|
String resourceType = myContext.getResourceDefinition(theResource).getName();
|
||||||
if (isNotBlank(theEntity.getResourceType()) && !theEntity.getResourceType().equals(resourceType)) {
|
if (isNotBlank(theEntity.getResourceType()) && !theEntity.getResourceType().equals(resourceType)) {
|
||||||
|
@ -1546,7 +1569,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
}
|
}
|
||||||
Long next = matches.iterator().next();
|
Long next = matches.iterator().next();
|
||||||
String newId = translatePidIdToForcedId(resourceTypeString, next);
|
String newId = translatePidIdToForcedId(resourceTypeString, next);
|
||||||
ourLog.info("Replacing inline match URL[{}] with ID[{}}", nextId.getValue(), newId);
|
ourLog.debug("Replacing inline match URL[{}] with ID[{}}", nextId.getValue(), newId);
|
||||||
nextRef.setReference(newId);
|
nextRef.setReference(newId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1612,7 +1635,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!changed.isChanged() && !theForceUpdate && myConfig.isSuppressUpdatesWithNoChange()) {
|
if (!changed.isChanged() && !theForceUpdate && myConfig.isSuppressUpdatesWithNoChange()) {
|
||||||
ourLog.info("Resource {} has not changed", theEntity.getIdDt().toUnqualified().getValue());
|
ourLog.debug("Resource {} has not changed", theEntity.getIdDt().toUnqualified().getValue());
|
||||||
if (theResource != null) {
|
if (theResource != null) {
|
||||||
populateResourceIdFromEntity(theEntity, theResource);
|
populateResourceIdFromEntity(theEntity, theResource);
|
||||||
}
|
}
|
||||||
|
@ -1654,7 +1677,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
historyEntry.setEncoding(changed.getEncoding());
|
historyEntry.setEncoding(changed.getEncoding());
|
||||||
historyEntry.setResource(changed.getResource());
|
historyEntry.setResource(changed.getResource());
|
||||||
|
|
||||||
ourLog.info("Saving history entry {}", historyEntry.getIdDt());
|
ourLog.debug("Saving history entry {}", historyEntry.getIdDt());
|
||||||
myResourceHistoryTableDao.save(historyEntry);
|
myResourceHistoryTableDao.save(historyEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1691,6 +1714,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
|
|
||||||
for (ResourceIndexedSearchParamString next : removeCommon(existingStringParams, stringParams)) {
|
for (ResourceIndexedSearchParamString next : removeCommon(existingStringParams, stringParams)) {
|
||||||
myEntityManager.remove(next);
|
myEntityManager.remove(next);
|
||||||
|
theEntity.getParamsString().remove(next);
|
||||||
}
|
}
|
||||||
for (ResourceIndexedSearchParamString next : removeCommon(stringParams, existingStringParams)) {
|
for (ResourceIndexedSearchParamString next : removeCommon(stringParams, existingStringParams)) {
|
||||||
myEntityManager.persist(next);
|
myEntityManager.persist(next);
|
||||||
|
@ -1698,6 +1722,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
|
|
||||||
for (ResourceIndexedSearchParamToken next : removeCommon(existingTokenParams, tokenParams)) {
|
for (ResourceIndexedSearchParamToken next : removeCommon(existingTokenParams, tokenParams)) {
|
||||||
myEntityManager.remove(next);
|
myEntityManager.remove(next);
|
||||||
|
theEntity.getParamsToken().remove(next);
|
||||||
}
|
}
|
||||||
for (ResourceIndexedSearchParamToken next : removeCommon(tokenParams, existingTokenParams)) {
|
for (ResourceIndexedSearchParamToken next : removeCommon(tokenParams, existingTokenParams)) {
|
||||||
myEntityManager.persist(next);
|
myEntityManager.persist(next);
|
||||||
|
@ -1705,6 +1730,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
|
|
||||||
for (ResourceIndexedSearchParamNumber next : removeCommon(existingNumberParams, numberParams)) {
|
for (ResourceIndexedSearchParamNumber next : removeCommon(existingNumberParams, numberParams)) {
|
||||||
myEntityManager.remove(next);
|
myEntityManager.remove(next);
|
||||||
|
theEntity.getParamsNumber().remove(next);
|
||||||
}
|
}
|
||||||
for (ResourceIndexedSearchParamNumber next : removeCommon(numberParams, existingNumberParams)) {
|
for (ResourceIndexedSearchParamNumber next : removeCommon(numberParams, existingNumberParams)) {
|
||||||
myEntityManager.persist(next);
|
myEntityManager.persist(next);
|
||||||
|
@ -1712,6 +1738,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
|
|
||||||
for (ResourceIndexedSearchParamQuantity next : removeCommon(existingQuantityParams, quantityParams)) {
|
for (ResourceIndexedSearchParamQuantity next : removeCommon(existingQuantityParams, quantityParams)) {
|
||||||
myEntityManager.remove(next);
|
myEntityManager.remove(next);
|
||||||
|
theEntity.getParamsQuantity().remove(next);
|
||||||
}
|
}
|
||||||
for (ResourceIndexedSearchParamQuantity next : removeCommon(quantityParams, existingQuantityParams)) {
|
for (ResourceIndexedSearchParamQuantity next : removeCommon(quantityParams, existingQuantityParams)) {
|
||||||
myEntityManager.persist(next);
|
myEntityManager.persist(next);
|
||||||
|
@ -1720,6 +1747,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
// Store date SP's
|
// Store date SP's
|
||||||
for (ResourceIndexedSearchParamDate next : removeCommon(existingDateParams, dateParams)) {
|
for (ResourceIndexedSearchParamDate next : removeCommon(existingDateParams, dateParams)) {
|
||||||
myEntityManager.remove(next);
|
myEntityManager.remove(next);
|
||||||
|
theEntity.getParamsDate().remove(next);
|
||||||
}
|
}
|
||||||
for (ResourceIndexedSearchParamDate next : removeCommon(dateParams, existingDateParams)) {
|
for (ResourceIndexedSearchParamDate next : removeCommon(dateParams, existingDateParams)) {
|
||||||
myEntityManager.persist(next);
|
myEntityManager.persist(next);
|
||||||
|
@ -1728,6 +1756,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
// Store URI SP's
|
// Store URI SP's
|
||||||
for (ResourceIndexedSearchParamUri next : removeCommon(existingUriParams, uriParams)) {
|
for (ResourceIndexedSearchParamUri next : removeCommon(existingUriParams, uriParams)) {
|
||||||
myEntityManager.remove(next);
|
myEntityManager.remove(next);
|
||||||
|
theEntity.getParamsUri().remove(next);
|
||||||
}
|
}
|
||||||
for (ResourceIndexedSearchParamUri next : removeCommon(uriParams, existingUriParams)) {
|
for (ResourceIndexedSearchParamUri next : removeCommon(uriParams, existingUriParams)) {
|
||||||
myEntityManager.persist(next);
|
myEntityManager.persist(next);
|
||||||
|
@ -1736,6 +1765,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
// Store Coords SP's
|
// Store Coords SP's
|
||||||
for (ResourceIndexedSearchParamCoords next : removeCommon(existingCoordsParams, coordsParams)) {
|
for (ResourceIndexedSearchParamCoords next : removeCommon(existingCoordsParams, coordsParams)) {
|
||||||
myEntityManager.remove(next);
|
myEntityManager.remove(next);
|
||||||
|
theEntity.getParamsCoords().remove(next);
|
||||||
}
|
}
|
||||||
for (ResourceIndexedSearchParamCoords next : removeCommon(coordsParams, existingCoordsParams)) {
|
for (ResourceIndexedSearchParamCoords next : removeCommon(coordsParams, existingCoordsParams)) {
|
||||||
myEntityManager.persist(next);
|
myEntityManager.persist(next);
|
||||||
|
@ -1744,6 +1774,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
// Store resource links
|
// Store resource links
|
||||||
for (ResourceLink next : removeCommon(existingResourceLinks, links)) {
|
for (ResourceLink next : removeCommon(existingResourceLinks, links)) {
|
||||||
myEntityManager.remove(next);
|
myEntityManager.remove(next);
|
||||||
|
theEntity.getResourceLinks().remove(next);
|
||||||
}
|
}
|
||||||
for (ResourceLink next : removeCommon(links, existingResourceLinks)) {
|
for (ResourceLink next : removeCommon(links, existingResourceLinks)) {
|
||||||
myEntityManager.persist(next);
|
myEntityManager.persist(next);
|
||||||
|
@ -1753,23 +1784,20 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
|
|
||||||
// Store composite string uniques
|
// Store composite string uniques
|
||||||
if (getConfig().isUniqueIndexesEnabled()) {
|
if (getConfig().isUniqueIndexesEnabled()) {
|
||||||
for (ResourceIndexedCompositeStringUnique next : existingCompositeStringUniques) {
|
for (ResourceIndexedCompositeStringUnique next : removeCommon(existingCompositeStringUniques, compositeStringUniques)) {
|
||||||
if (!compositeStringUniques.contains(next)) {
|
ourLog.debug("Removing unique index: {}", next);
|
||||||
ourLog.debug("Removing unique index: {}", next);
|
myEntityManager.remove(next);
|
||||||
myEntityManager.remove(next);
|
theEntity.getParamsCompositeStringUnique().remove(next);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (ResourceIndexedCompositeStringUnique next : compositeStringUniques) {
|
for (ResourceIndexedCompositeStringUnique next : removeCommon(compositeStringUniques, existingCompositeStringUniques)) {
|
||||||
if (!existingCompositeStringUniques.contains(next)) {
|
if (myConfig.isUniqueIndexesCheckedBeforeSave()) {
|
||||||
if (myConfig.isUniqueIndexesCheckedBeforeSave()) {
|
ResourceIndexedCompositeStringUnique existing = myResourceIndexedCompositeStringUniqueDao.findByQueryString(next.getIndexString());
|
||||||
ResourceIndexedCompositeStringUnique existing = myResourceIndexedCompositeStringUniqueDao.findByQueryString(next.getIndexString());
|
if (existing != null) {
|
||||||
if (existing != null) {
|
throw new PreconditionFailedException("Can not create resource of type " + theEntity.getResourceType() + " as it would create a duplicate index matching query: " + next.getIndexString() + " (existing index belongs to " + existing.getResource().getIdDt().toUnqualifiedVersionless().getValue() + ")");
|
||||||
throw new PreconditionFailedException("Can not create resource of type " + theEntity.getResourceType() + " as it would create a duplicate index matching query: " + next.getIndexString() + " (existing index belongs to " + existing.getResource().getIdDt().toUnqualifiedVersionless().getValue() + ")");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ourLog.debug("Persisting unique index: {}", next);
|
|
||||||
myEntityManager.persist(next);
|
|
||||||
}
|
}
|
||||||
|
ourLog.debug("Persisting unique index: {}", next);
|
||||||
|
myEntityManager.persist(next);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1813,7 +1841,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
|
|
||||||
if (nextChildDef instanceof RuntimeChildResourceDefinition) {
|
if (nextChildDef instanceof RuntimeChildResourceDefinition) {
|
||||||
RuntimeChildResourceDefinition nextChildDefRes = (RuntimeChildResourceDefinition) nextChildDef;
|
RuntimeChildResourceDefinition nextChildDefRes = (RuntimeChildResourceDefinition) nextChildDef;
|
||||||
Set<String> validTypes = new HashSet<String>();
|
Set<String> validTypes = new HashSet<>();
|
||||||
boolean allowAny = false;
|
boolean allowAny = false;
|
||||||
for (Class<? extends IBaseResource> nextValidType : nextChildDefRes.getResourceTypes()) {
|
for (Class<? extends IBaseResource> nextValidType : nextChildDefRes.getResourceTypes()) {
|
||||||
if (nextValidType.isInterface()) {
|
if (nextValidType.isInterface()) {
|
||||||
|
@ -2105,6 +2133,14 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
return b.toString();
|
return b.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do not call this method outside of unit tests
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
public static void setValidationDisabledForUnitTest(boolean theValidationDisabledForUnitTest) {
|
||||||
|
ourValidationDisabledForUnitTest = theValidationDisabledForUnitTest;
|
||||||
|
}
|
||||||
|
|
||||||
private static List<BaseCodingDt> toBaseCodingList(List<IBaseCoding> theSecurityLabels) {
|
private static List<BaseCodingDt> toBaseCodingList(List<IBaseCoding> theSecurityLabels) {
|
||||||
ArrayList<BaseCodingDt> retVal = new ArrayList<BaseCodingDt>(theSecurityLabels.size());
|
ArrayList<BaseCodingDt> retVal = new ArrayList<BaseCodingDt>(theSecurityLabels.size());
|
||||||
for (IBaseCoding next : theSecurityLabels) {
|
for (IBaseCoding next : theSecurityLabels) {
|
||||||
|
@ -2131,7 +2167,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (forcedId.isEmpty() == false) {
|
if (forcedId.isEmpty() == false) {
|
||||||
List<Long> retVal = new ArrayList<Long>(forcedId.size());
|
List<Long> retVal = new ArrayList<>(forcedId.size());
|
||||||
for (ForcedId next : forcedId) {
|
for (ForcedId next : forcedId) {
|
||||||
retVal.add(next.getResourcePid());
|
retVal.add(next.getResourcePid());
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ import ca.uhn.fhir.jpa.entity.*;
|
||||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||||
import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider;
|
import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider;
|
||||||
import ca.uhn.fhir.jpa.util.DeleteConflict;
|
import ca.uhn.fhir.jpa.util.DeleteConflict;
|
||||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import ca.uhn.fhir.jpa.util.jsonpatch.JsonPatchUtils;
|
import ca.uhn.fhir.jpa.util.jsonpatch.JsonPatchUtils;
|
||||||
import ca.uhn.fhir.jpa.util.xmlpatch.XmlPatchUtils;
|
import ca.uhn.fhir.jpa.util.xmlpatch.XmlPatchUtils;
|
||||||
import ca.uhn.fhir.model.api.*;
|
import ca.uhn.fhir.model.api.*;
|
||||||
|
@ -56,6 +56,7 @@ import org.apache.commons.lang3.Validate;
|
||||||
import org.hl7.fhir.instance.model.api.*;
|
import org.hl7.fhir.instance.model.api.*;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Required;
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
import org.springframework.transaction.TransactionDefinition;
|
import org.springframework.transaction.TransactionDefinition;
|
||||||
import org.springframework.transaction.TransactionStatus;
|
import org.springframework.transaction.TransactionStatus;
|
||||||
|
@ -126,7 +127,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLog.info("Processed addTag {}/{} on {} in {}ms", new Object[]{theScheme, theTerm, theId, w.getMillisAndRestart()});
|
ourLog.debug("Processed addTag {}/{} on {} in {}ms", theScheme, theTerm, theId, w.getMillisAndRestart());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -272,7 +273,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
|
|
||||||
validateDeleteConflictsEmptyOrThrowException(deleteConflicts);
|
validateDeleteConflictsEmptyOrThrowException(deleteConflicts);
|
||||||
|
|
||||||
ourLog.info("Processed delete on {} in {}ms", theId.getValue(), w.getMillisAndRestart());
|
ourLog.debug("Processed delete on {} in {}ms", theId.getValue(), w.getMillisAndRestart());
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,7 +350,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
OperationOutcomeUtil.addIssue(getContext(), oo, severity, message, null, code);
|
OperationOutcomeUtil.addIssue(getContext(), oo, severity, message, null, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLog.info("Processed delete on {} (matched {} resource(s)) in {}ms", new Object[]{theUrl, deletedResources.size(), w.getMillis()});
|
ourLog.debug("Processed delete on {} (matched {} resource(s)) in {}ms", theUrl, deletedResources.size(), w.getMillis());
|
||||||
|
|
||||||
DeleteMethodOutcome retVal = new DeleteMethodOutcome();
|
DeleteMethodOutcome retVal = new DeleteMethodOutcome();
|
||||||
retVal.setDeletedEntities(deletedResources);
|
retVal.setDeletedEntities(deletedResources);
|
||||||
|
@ -461,7 +462,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "successfulCreate", outcome.getId(), w.getMillisAndRestart());
|
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "successfulCreate", outcome.getId(), w.getMillisAndRestart());
|
||||||
outcome.setOperationOutcome(createInfoOperationOutcome(msg));
|
outcome.setOperationOutcome(createInfoOperationOutcome(msg));
|
||||||
|
|
||||||
ourLog.info(msg);
|
ourLog.debug(msg);
|
||||||
return outcome;
|
return outcome;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,7 +530,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
|
|
||||||
StopWatch w = new StopWatch();
|
StopWatch w = new StopWatch();
|
||||||
TagList tags = super.getTags(myResourceType, null);
|
TagList tags = super.getTags(myResourceType, null);
|
||||||
ourLog.info("Processed getTags on {} in {}ms", myResourceName, w.getMillisAndRestart());
|
ourLog.debug("Processed getTags on {} in {}ms", myResourceName, w.getMillisAndRestart());
|
||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -556,7 +557,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
|
|
||||||
StopWatch w = new StopWatch();
|
StopWatch w = new StopWatch();
|
||||||
TagList retVal = super.getTags(myResourceType, theResourceId);
|
TagList retVal = super.getTags(myResourceType, theResourceId);
|
||||||
ourLog.info("Processed getTags on {} in {}ms", theResourceId, w.getMillisAndRestart());
|
ourLog.debug("Processed getTags on {} in {}ms", theResourceId, w.getMillisAndRestart());
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -568,7 +569,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
|
|
||||||
StopWatch w = new StopWatch();
|
StopWatch w = new StopWatch();
|
||||||
IBundleProvider retVal = super.history(myResourceName, null, theSince, theUntil);
|
IBundleProvider retVal = super.history(myResourceName, null, theSince, theUntil);
|
||||||
ourLog.info("Processed history on {} in {}ms", myResourceName, w.getMillisAndRestart());
|
ourLog.debug("Processed history on {} in {}ms", myResourceName, w.getMillisAndRestart());
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -585,7 +586,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
|
|
||||||
IBundleProvider retVal = super.history(myResourceName, entity.getId(), theSince, theUntil);
|
IBundleProvider retVal = super.history(myResourceName, entity.getId(), theSince, theUntil);
|
||||||
|
|
||||||
ourLog.info("Processed history on {} in {}ms", id, w.getMillisAndRestart());
|
ourLog.debug("Processed history on {} in {}ms", id, w.getMillisAndRestart());
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -612,25 +613,31 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
return theRequestDetails.getServer().getPagingProvider() instanceof DatabaseBackedPagingProvider;
|
return theRequestDetails.getServer().getPagingProvider() instanceof DatabaseBackedPagingProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void markResourcesMatchingExpressionAsNeedingReindexing(String theExpression) {
|
protected void markResourcesMatchingExpressionAsNeedingReindexing(Boolean theCurrentlyReindexing, String theExpression) {
|
||||||
|
// Avoid endless loops
|
||||||
|
if (Boolean.TRUE.equals(theCurrentlyReindexing)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (myDaoConfig.isMarkResourcesForReindexingUponSearchParameterChange()) {
|
if (myDaoConfig.isMarkResourcesForReindexingUponSearchParameterChange()) {
|
||||||
if (isNotBlank(theExpression)) {
|
if (isNotBlank(theExpression)) {
|
||||||
final String resourceType = theExpression.substring(0, theExpression.indexOf('.'));
|
final String resourceType = theExpression.substring(0, theExpression.indexOf('.'));
|
||||||
ourLog.info("Marking all resources of type {} for reindexing due to updated search parameter with path: {}", resourceType, theExpression);
|
ourLog.debug("Marking all resources of type {} for reindexing due to updated search parameter with path: {}", resourceType, theExpression);
|
||||||
|
|
||||||
TransactionTemplate txTemplate = new TransactionTemplate(myPlatformTransactionManager);
|
TransactionTemplate txTemplate = new TransactionTemplate(myPlatformTransactionManager);
|
||||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||||
int updatedCount = txTemplate.execute(new TransactionCallback<Integer>() {
|
Integer updatedCount = txTemplate.execute(new TransactionCallback<Integer>() {
|
||||||
@Override
|
@Override
|
||||||
public Integer doInTransaction(TransactionStatus theStatus) {
|
public @NonNull Integer doInTransaction(TransactionStatus theStatus) {
|
||||||
return myResourceTableDao.markResourcesOfTypeAsRequiringReindexing(resourceType);
|
return myResourceTableDao.markResourcesOfTypeAsRequiringReindexing(resourceType);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ourLog.info("Marked {} resources for reindexing", updatedCount);
|
ourLog.debug("Marked {} resources for reindexing", updatedCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mySearchParamRegistry.forceRefresh();
|
|
||||||
|
mySearchParamRegistry.requestRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -658,7 +665,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
doMetaAdd(theMetaAdd, history);
|
doMetaAdd(theMetaAdd, history);
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLog.info("Processed metaAddOperation on {} in {}ms", new Object[]{theResourceId, w.getMillisAndRestart()});
|
ourLog.debug("Processed metaAddOperation on {} in {}ms", new Object[]{theResourceId, w.getMillisAndRestart()});
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
MT retVal = (MT) metaGetOperation(theMetaAdd.getClass(), theResourceId, theRequestDetails);
|
MT retVal = (MT) metaGetOperation(theMetaAdd.getClass(), theResourceId, theRequestDetails);
|
||||||
|
@ -692,7 +699,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
|
|
||||||
myEntityManager.flush();
|
myEntityManager.flush();
|
||||||
|
|
||||||
ourLog.info("Processed metaDeleteOperation on {} in {}ms", new Object[]{theResourceId.getValue(), w.getMillisAndRestart()});
|
ourLog.debug("Processed metaDeleteOperation on {} in {}ms", new Object[]{theResourceId.getValue(), w.getMillisAndRestart()});
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
MT retVal = (MT) metaGetOperation(theMetaDel.getClass(), theResourceId, theRequestDetails);
|
MT retVal = (MT) metaGetOperation(theMetaDel.getClass(), theResourceId, theRequestDetails);
|
||||||
|
@ -707,7 +714,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
notifyInterceptors(RestOperationTypeEnum.META, requestDetails);
|
notifyInterceptors(RestOperationTypeEnum.META, requestDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<TagDefinition> tagDefs = new HashSet<TagDefinition>();
|
Set<TagDefinition> tagDefs = new HashSet<>();
|
||||||
BaseHasResource entity = readEntity(theId);
|
BaseHasResource entity = readEntity(theId);
|
||||||
for (BaseTag next : entity.getTags()) {
|
for (BaseTag next : entity.getTags()) {
|
||||||
tagDefs.add(next.getTag());
|
tagDefs.add(next.getTag());
|
||||||
|
@ -733,9 +740,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
q.setParameter("res_type", myResourceName);
|
q.setParameter("res_type", myResourceName);
|
||||||
List<TagDefinition> tagDefinitions = q.getResultList();
|
List<TagDefinition> tagDefinitions = q.getResultList();
|
||||||
|
|
||||||
MT retVal = toMetaDt(theType, tagDefinitions);
|
return toMetaDt(theType, tagDefinitions);
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -859,15 +864,14 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
throw new ResourceGoneException("Resource was deleted at " + deleted.getValueAsString());
|
throw new ResourceGoneException("Resource was deleted at " + deleted.getValueAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLog.info("Processed read on {} in {}ms", theId.getValue(), w.getMillisAndRestart());
|
ourLog.debug("Processed read on {} in {}ms", theId.getValue(), w.getMillisAndRestart());
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BaseHasResource readEntity(IIdType theId) {
|
public BaseHasResource readEntity(IIdType theId) {
|
||||||
BaseHasResource entity = readEntity(theId, true);
|
|
||||||
|
|
||||||
return entity;
|
return readEntity(theId, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -885,7 +889,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
if (theId.isVersionIdPartValidLong() == false) {
|
if (theId.isVersionIdPartValidLong() == false) {
|
||||||
throw new ResourceNotFoundException(getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "invalidVersion", theId.getVersionIdPart(), theId.toUnqualifiedVersionless()));
|
throw new ResourceNotFoundException(getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "invalidVersion", theId.getVersionIdPart(), theId.toUnqualifiedVersionless()));
|
||||||
}
|
}
|
||||||
if (entity.getVersion() != theId.getVersionIdPartAsLong().longValue()) {
|
if (entity.getVersion() != theId.getVersionIdPartAsLong()) {
|
||||||
entity = null;
|
entity = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -925,7 +929,9 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
@Override
|
@Override
|
||||||
public void reindex(T theResource, ResourceTable theEntity) {
|
public void reindex(T theResource, ResourceTable theEntity) {
|
||||||
ourLog.debug("Indexing resource {} - PID {}", theResource.getIdElement().getValue(), theEntity.getId());
|
ourLog.debug("Indexing resource {} - PID {}", theResource.getIdElement().getValue(), theEntity.getId());
|
||||||
|
CURRENTLY_REINDEXING.put(theResource, Boolean.TRUE);
|
||||||
updateEntity(theResource, theEntity, null, true, false, theEntity.getUpdatedDate(), true, false);
|
updateEntity(theResource, theEntity, null, true, false, theEntity.getUpdatedDate(), true, false);
|
||||||
|
CURRENTLY_REINDEXING.put(theResource, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -962,7 +968,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
|
|
||||||
myEntityManager.merge(entity);
|
myEntityManager.merge(entity);
|
||||||
|
|
||||||
ourLog.info("Processed remove tag {}/{} on {} in {}ms", new Object[]{theScheme, theTerm, theId.getValue(), w.getMillisAndRestart()});
|
ourLog.debug("Processed remove tag {}/{} on {} in {}ms", theScheme, theTerm, theId.getValue(), w.getMillisAndRestart());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(propagation = Propagation.SUPPORTS)
|
@Transactional(propagation = Propagation.SUPPORTS)
|
||||||
|
@ -1276,7 +1282,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "successfulCreate", outcome.getId(), w.getMillisAndRestart());
|
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "successfulCreate", outcome.getId(), w.getMillisAndRestart());
|
||||||
outcome.setOperationOutcome(createInfoOperationOutcome(msg));
|
outcome.setOperationOutcome(createInfoOperationOutcome(msg));
|
||||||
|
|
||||||
ourLog.info(msg);
|
ourLog.debug(msg);
|
||||||
return outcome;
|
return outcome;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1333,7 +1339,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
}
|
}
|
||||||
|
|
||||||
if (myDaoConfig.isEnforceReferentialIntegrityOnDelete() == false && !theForValidate) {
|
if (myDaoConfig.isEnforceReferentialIntegrityOnDelete() == false && !theForValidate) {
|
||||||
ourLog.info("Deleting {} resource dependencies which can no longer be satisfied", resultList.size());
|
ourLog.debug("Deleting {} resource dependencies which can no longer be satisfied", resultList.size());
|
||||||
myResourceLinkDao.delete(resultList);
|
myResourceLinkDao.delete(resultList);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import ca.uhn.fhir.jpa.dao.data.ITermConceptDao;
|
||||||
import ca.uhn.fhir.jpa.entity.ForcedId;
|
import ca.uhn.fhir.jpa.entity.ForcedId;
|
||||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.util.ReindexFailureException;
|
import ca.uhn.fhir.jpa.util.ReindexFailureException;
|
||||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
|
@ -66,13 +66,21 @@ public abstract class BaseHapiFhirSystemDao<T, MT> extends BaseHapiFhirDao<IBase
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ITermConceptDao myTermConceptDao;
|
private ITermConceptDao myTermConceptDao;
|
||||||
|
@Autowired
|
||||||
|
private ISearchParamRegistry mySearchParamRegistry;
|
||||||
@Autowired
|
@Autowired
|
||||||
private PlatformTransactionManager myTxManager;
|
private PlatformTransactionManager myTxManager;
|
||||||
@Autowired
|
@Autowired
|
||||||
private IResourceTableDao myResourceTableDao;
|
private IResourceTableDao myResourceTableDao;
|
||||||
|
|
||||||
private int doPerformReindexingPass(final Integer theCount) {
|
private int doPerformReindexingPass(final Integer theCount) {
|
||||||
|
/*
|
||||||
|
* If any search parameters have been recently added or changed,
|
||||||
|
* this makes sure that the cache has been reloaded to reflect
|
||||||
|
* them.
|
||||||
|
*/
|
||||||
|
mySearchParamRegistry.refreshCacheIfNecessary();
|
||||||
|
|
||||||
TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
|
TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
|
||||||
txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRED);
|
txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRED);
|
||||||
return doPerformReindexingPassForResources(theCount, txTemplate);
|
return doPerformReindexingPassForResources(theCount, txTemplate);
|
||||||
|
|
|
@ -24,17 +24,25 @@ import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.jpa.search.JpaRuntimeSearchParam;
|
import ca.uhn.fhir.jpa.search.JpaRuntimeSearchParam;
|
||||||
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
|
import ca.uhn.fhir.util.SearchParameterUtil;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public abstract class BaseSearchParamRegistry implements ISearchParamRegistry {
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
|
||||||
|
public abstract class BaseSearchParamRegistry<SP extends IBaseResource> implements ISearchParamRegistry {
|
||||||
|
|
||||||
|
private static final int MAX_MANAGED_PARAM_COUNT = 10000;
|
||||||
private static final Logger ourLog = LoggerFactory.getLogger(BaseSearchParamRegistry.class);
|
private static final Logger ourLog = LoggerFactory.getLogger(BaseSearchParamRegistry.class);
|
||||||
private Map<String, Map<String, RuntimeSearchParam>> myBuiltInSearchParams;
|
private Map<String, Map<String, RuntimeSearchParam>> myBuiltInSearchParams;
|
||||||
private volatile Map<String, List<JpaRuntimeSearchParam>> myActiveUniqueSearchParams = Collections.emptyMap();
|
private volatile Map<String, List<JpaRuntimeSearchParam>> myActiveUniqueSearchParams = Collections.emptyMap();
|
||||||
|
@ -43,14 +51,26 @@ public abstract class BaseSearchParamRegistry implements ISearchParamRegistry {
|
||||||
private FhirContext myCtx;
|
private FhirContext myCtx;
|
||||||
@Autowired
|
@Autowired
|
||||||
private Collection<IFhirResourceDao<?>> myDaos;
|
private Collection<IFhirResourceDao<?>> myDaos;
|
||||||
|
private volatile Map<String, Map<String, RuntimeSearchParam>> myActiveSearchParams;
|
||||||
|
@Autowired
|
||||||
|
private DaoConfig myDaoConfig;
|
||||||
|
private volatile long myLastRefresh;
|
||||||
|
|
||||||
public BaseSearchParamRegistry() {
|
public BaseSearchParamRegistry() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void requestRefresh() {
|
||||||
|
synchronized (this) {
|
||||||
|
myLastRefresh = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void forceRefresh() {
|
public void forceRefresh() {
|
||||||
// nothing by default
|
requestRefresh();
|
||||||
|
refreshCacheIfNecessary();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -63,21 +83,19 @@ public abstract class BaseSearchParamRegistry implements ISearchParamRegistry {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Map<String, RuntimeSearchParam>> getActiveSearchParams() {
|
public Map<String, Map<String, RuntimeSearchParam>> getActiveSearchParams() {
|
||||||
return myBuiltInSearchParams;
|
return myActiveSearchParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, RuntimeSearchParam> getActiveSearchParams(String theResourceName) {
|
public Map<String, RuntimeSearchParam> getActiveSearchParams(String theResourceName) {
|
||||||
Validate.notBlank(theResourceName, "theResourceName must not be blank or null");
|
return myActiveSearchParams.get(theResourceName);
|
||||||
|
|
||||||
return myBuiltInSearchParams.get(theResourceName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<JpaRuntimeSearchParam> getActiveUniqueSearchParams(String theResourceName) {
|
public List<JpaRuntimeSearchParam> getActiveUniqueSearchParams(String theResourceName) {
|
||||||
refreshCacheIfNecessary();
|
|
||||||
List<JpaRuntimeSearchParam> retVal = myActiveUniqueSearchParams.get(theResourceName);
|
List<JpaRuntimeSearchParam> retVal = myActiveUniqueSearchParams.get(theResourceName);
|
||||||
if (retVal == null) {
|
if (retVal == null) {
|
||||||
retVal = Collections.emptyList();
|
retVal = Collections.emptyList();
|
||||||
|
@ -87,7 +105,6 @@ public abstract class BaseSearchParamRegistry implements ISearchParamRegistry {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<JpaRuntimeSearchParam> getActiveUniqueSearchParams(String theResourceName, Set<String> theParamNames) {
|
public List<JpaRuntimeSearchParam> getActiveUniqueSearchParams(String theResourceName, Set<String> theParamNames) {
|
||||||
refreshCacheIfNecessary();
|
|
||||||
|
|
||||||
Map<Set<String>, List<JpaRuntimeSearchParam>> paramNamesToParams = myActiveParamNamesToUniqueSearchParams.get(theResourceName);
|
Map<Set<String>, List<JpaRuntimeSearchParam>> paramNamesToParams = myActiveParamNamesToUniqueSearchParams.get(theResourceName);
|
||||||
if (paramNamesToParams == null) {
|
if (paramNamesToParams == null) {
|
||||||
|
@ -105,7 +122,18 @@ public abstract class BaseSearchParamRegistry implements ISearchParamRegistry {
|
||||||
return myBuiltInSearchParams;
|
return myBuiltInSearchParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void populateActiveSearchParams(Map<String, Map<String, RuntimeSearchParam>> theActiveSearchParams) {
|
private Map<String, RuntimeSearchParam> getSearchParamMap(Map<String, Map<String, RuntimeSearchParam>> searchParams, String theResourceName) {
|
||||||
|
Map<String, RuntimeSearchParam> retVal = searchParams.get(theResourceName);
|
||||||
|
if (retVal == null) {
|
||||||
|
retVal = new HashMap<>();
|
||||||
|
searchParams.put(theResourceName, retVal);
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract IFhirResourceDao<SP> getSearchParameterDao();
|
||||||
|
|
||||||
|
private void populateActiveSearchParams(Map<String, Map<String, RuntimeSearchParam>> theActiveSearchParams) {
|
||||||
Map<String, List<JpaRuntimeSearchParam>> activeUniqueSearchParams = new HashMap<>();
|
Map<String, List<JpaRuntimeSearchParam>> activeUniqueSearchParams = new HashMap<>();
|
||||||
Map<String, Map<Set<String>, List<JpaRuntimeSearchParam>>> activeParamNamesToUniqueSearchParams = new HashMap<>();
|
Map<String, Map<Set<String>, List<JpaRuntimeSearchParam>>> activeParamNamesToUniqueSearchParams = new HashMap<>();
|
||||||
|
|
||||||
|
@ -196,8 +224,100 @@ public abstract class BaseSearchParamRegistry implements ISearchParamRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
myBuiltInSearchParams = Collections.unmodifiableMap(resourceNameToSearchParams);
|
myBuiltInSearchParams = Collections.unmodifiableMap(resourceNameToSearchParams);
|
||||||
|
|
||||||
|
refreshCacheIfNecessary();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void refreshCacheIfNecessary();
|
@Override
|
||||||
|
public void refreshCacheIfNecessary() {
|
||||||
|
long refreshInterval = 60 * DateUtils.MILLIS_PER_MINUTE;
|
||||||
|
if (System.currentTimeMillis() - refreshInterval > myLastRefresh) {
|
||||||
|
synchronized (this) {
|
||||||
|
if (System.currentTimeMillis() - refreshInterval > myLastRefresh) {
|
||||||
|
StopWatch sw = new StopWatch();
|
||||||
|
|
||||||
|
Map<String, Map<String, RuntimeSearchParam>> searchParams = new HashMap<>();
|
||||||
|
for (Map.Entry<String, Map<String, RuntimeSearchParam>> nextBuiltInEntry : getBuiltInSearchParams().entrySet()) {
|
||||||
|
for (RuntimeSearchParam nextParam : nextBuiltInEntry.getValue().values()) {
|
||||||
|
String nextResourceName = nextBuiltInEntry.getKey();
|
||||||
|
getSearchParamMap(searchParams, nextResourceName).put(nextParam.getName(), nextParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchParameterMap params = new SearchParameterMap();
|
||||||
|
params.setLoadSynchronousUpTo(MAX_MANAGED_PARAM_COUNT);
|
||||||
|
|
||||||
|
IBundleProvider allSearchParamsBp = getSearchParameterDao().search(params);
|
||||||
|
int size = allSearchParamsBp.size();
|
||||||
|
|
||||||
|
// Just in case..
|
||||||
|
if (size >= MAX_MANAGED_PARAM_COUNT) {
|
||||||
|
ourLog.warn("Unable to support >" + MAX_MANAGED_PARAM_COUNT + " search params!");
|
||||||
|
size = MAX_MANAGED_PARAM_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<IBaseResource> allSearchParams = allSearchParamsBp.getResources(0, size);
|
||||||
|
for (IBaseResource nextResource : allSearchParams) {
|
||||||
|
SP nextSp = (SP) nextResource;
|
||||||
|
RuntimeSearchParam runtimeSp = toRuntimeSp(nextSp);
|
||||||
|
if (runtimeSp == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String nextBaseName : SearchParameterUtil.getBaseAsStrings(myCtx, nextSp)) {
|
||||||
|
if (isBlank(nextBaseName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, RuntimeSearchParam> searchParamMap = getSearchParamMap(searchParams, nextBaseName);
|
||||||
|
String name = runtimeSp.getName();
|
||||||
|
if (myDaoConfig.isDefaultSearchParamsCanBeOverridden() || !searchParamMap.containsKey(name)) {
|
||||||
|
searchParamMap.put(name, runtimeSp);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Map<String, RuntimeSearchParam>> activeSearchParams = new HashMap<>();
|
||||||
|
for (Map.Entry<String, Map<String, RuntimeSearchParam>> nextEntry : searchParams.entrySet()) {
|
||||||
|
for (RuntimeSearchParam nextSp : nextEntry.getValue().values()) {
|
||||||
|
String nextName = nextSp.getName();
|
||||||
|
if (nextSp.getStatus() != RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE) {
|
||||||
|
nextSp = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!activeSearchParams.containsKey(nextEntry.getKey())) {
|
||||||
|
activeSearchParams.put(nextEntry.getKey(), new HashMap<String, RuntimeSearchParam>());
|
||||||
|
}
|
||||||
|
if (activeSearchParams.containsKey(nextEntry.getKey())) {
|
||||||
|
ourLog.debug("Replacing existing/built in search param {}:{} with new one", nextEntry.getKey(), nextName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextSp != null) {
|
||||||
|
activeSearchParams.get(nextEntry.getKey()).put(nextName, nextSp);
|
||||||
|
} else {
|
||||||
|
activeSearchParams.get(nextEntry.getKey()).remove(nextName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
myActiveSearchParams = activeSearchParams;
|
||||||
|
|
||||||
|
populateActiveSearchParams(activeSearchParams);
|
||||||
|
|
||||||
|
myLastRefresh = System.currentTimeMillis();
|
||||||
|
ourLog.info("Refreshed search parameter cache in {}ms", sw.getMillis());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Scheduled(fixedDelay = 10 * DateUtils.MILLIS_PER_SECOND)
|
||||||
|
public void refreshCacheOnSchedule() {
|
||||||
|
refreshCacheIfNecessary();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract RuntimeSearchParam toRuntimeSp(SP theNextSp);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,9 @@ public class FhirResourceDaoSearchParameterDstu2 extends FhirResourceDaoDstu2<Se
|
||||||
private IFhirSystemDao<Bundle, MetaDt> mySystemDao;
|
private IFhirSystemDao<Bundle, MetaDt> mySystemDao;
|
||||||
|
|
||||||
protected void markAffectedResources(SearchParameter theResource) {
|
protected void markAffectedResources(SearchParameter theResource) {
|
||||||
markResourcesMatchingExpressionAsNeedingReindexing(theResource != null ? theResource.getXpath() : null);
|
Boolean reindex = theResource != null ? CURRENTLY_REINDEXING.get(theResource) : null;
|
||||||
|
String expression = theResource != null ? theResource.getXpath() : null;
|
||||||
|
markResourcesMatchingExpressionAsNeedingReindexing(reindex, expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -25,6 +25,7 @@ import java.util.*;
|
||||||
|
|
||||||
import javax.persistence.TypedQuery;
|
import javax.persistence.TypedQuery;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.model.primitive.UriDt;
|
||||||
import org.apache.http.NameValuePair;
|
import org.apache.http.NameValuePair;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
@ -453,6 +454,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// References
|
||||||
List<BaseResourceReferenceDt> allRefs = terser.getAllPopulatedChildElementsOfType(nextResource, BaseResourceReferenceDt.class);
|
List<BaseResourceReferenceDt> allRefs = terser.getAllPopulatedChildElementsOfType(nextResource, BaseResourceReferenceDt.class);
|
||||||
for (BaseResourceReferenceDt nextRef : allRefs) {
|
for (BaseResourceReferenceDt nextRef : allRefs) {
|
||||||
IdDt nextId = nextRef.getReference();
|
IdDt nextId = nextRef.getReference();
|
||||||
|
@ -461,13 +463,30 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
||||||
}
|
}
|
||||||
if (idSubstitutions.containsKey(nextId)) {
|
if (idSubstitutions.containsKey(nextId)) {
|
||||||
IdDt newId = idSubstitutions.get(nextId);
|
IdDt newId = idSubstitutions.get(nextId);
|
||||||
ourLog.info(" * Replacing resource ref {} with {}", nextId, newId);
|
ourLog.debug(" * Replacing resource ref {} with {}", nextId, newId);
|
||||||
nextRef.setReference(newId);
|
nextRef.setReference(newId);
|
||||||
} else {
|
} else {
|
||||||
ourLog.debug(" * Reference [{}] does not exist in bundle", nextId);
|
ourLog.debug(" * Reference [{}] does not exist in bundle", nextId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// URIs
|
||||||
|
List<UriDt> allUris = terser.getAllPopulatedChildElementsOfType(nextResource, UriDt.class);
|
||||||
|
for (UriDt nextRef : allUris) {
|
||||||
|
if (nextRef instanceof IIdType) {
|
||||||
|
continue; // No substitution on the resource ID itself!
|
||||||
|
}
|
||||||
|
IdDt nextUriString = new IdDt(nextRef.getValueAsString());
|
||||||
|
if (idSubstitutions.containsKey(nextUriString)) {
|
||||||
|
IdDt newId = idSubstitutions.get(nextUriString);
|
||||||
|
ourLog.debug(" * Replacing resource ref {} with {}", nextUriString, newId);
|
||||||
|
nextRef.setValue(newId.getValue());
|
||||||
|
} else {
|
||||||
|
ourLog.debug(" * Reference [{}] does not exist in bundle", nextUriString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
InstantDt deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get(nextResource);
|
InstantDt deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get(nextResource);
|
||||||
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
||||||
boolean shouldUpdate = !nonUpdatedEntities.contains(nextOutcome.getEntity());
|
boolean shouldUpdate = !nonUpdatedEntities.contains(nextOutcome.getEntity());
|
||||||
|
@ -503,7 +522,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
||||||
if (replacement.equals(next)) {
|
if (replacement.equals(next)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ourLog.info("Placeholder resource ID \"{}\" was replaced with permanent ID \"{}\"", next, replacement);
|
ourLog.debug("Placeholder resource ID \"{}\" was replaced with permanent ID \"{}\"", next, replacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -532,7 +551,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
||||||
}
|
}
|
||||||
for (java.util.Map.Entry<String, Collection<String>> nextParamEntry : paramValues.asMap().entrySet()) {
|
for (java.util.Map.Entry<String, Collection<String>> nextParamEntry : paramValues.asMap().entrySet()) {
|
||||||
String[] nextValue = nextParamEntry.getValue().toArray(new String[nextParamEntry.getValue().size()]);
|
String[] nextValue = nextParamEntry.getValue().toArray(new String[nextParamEntry.getValue().size()]);
|
||||||
requestDetails.getParameters().put(nextParamEntry.getKey(), nextValue);
|
requestDetails.addParameter(nextParamEntry.getKey(), nextValue);
|
||||||
}
|
}
|
||||||
url = url.substring(0, qIndex);
|
url = url.substring(0, qIndex);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
package ca.uhn.fhir.jpa.dao;
|
package ca.uhn.fhir.jpa.dao;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.jpa.entity.BaseHasResource;
|
import ca.uhn.fhir.jpa.entity.BaseHasResource;
|
||||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider;
|
import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider;
|
||||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum.ResourceMetadataKeySupportingAnyResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* #%L
|
* #%L
|
||||||
|
@ -35,7 +33,9 @@ import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum.ResourceMetadataKeySupporti
|
||||||
|
|
||||||
public interface IDao {
|
public interface IDao {
|
||||||
|
|
||||||
ResourceMetadataKeySupportingAnyResource<Long, Long> RESOURCE_PID = new MetadataKeyResourcePid("RESOURCE_PID");
|
MetadataKeyResourcePid RESOURCE_PID = new MetadataKeyResourcePid("RESOURCE_PID");
|
||||||
|
|
||||||
|
MetadataKeyCurrentlyReindexing CURRENTLY_REINDEXING = new MetadataKeyCurrentlyReindexing("CURRENTLY_REINDEXING");
|
||||||
|
|
||||||
FhirContext getContext();
|
FhirContext getContext();
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,9 @@ import java.util.Set;
|
||||||
|
|
||||||
public interface ISearchParamRegistry {
|
public interface ISearchParamRegistry {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request that the cache be refreshed now, in the current thread
|
||||||
|
*/
|
||||||
void forceRefresh();
|
void forceRefresh();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,11 +39,18 @@ public interface ISearchParamRegistry {
|
||||||
*/
|
*/
|
||||||
RuntimeSearchParam getActiveSearchParam(String theResourceName, String theParamName);
|
RuntimeSearchParam getActiveSearchParam(String theResourceName, String theParamName);
|
||||||
|
|
||||||
|
Map<String, Map<String, RuntimeSearchParam>> getActiveSearchParams();
|
||||||
|
|
||||||
Map<String, RuntimeSearchParam> getActiveSearchParams(String theResourceName);
|
Map<String, RuntimeSearchParam> getActiveSearchParams(String theResourceName);
|
||||||
|
|
||||||
Map<String, Map<String, RuntimeSearchParam>> getActiveSearchParams();
|
List<JpaRuntimeSearchParam> getActiveUniqueSearchParams(String theResourceName, Set<String> theParamNames);
|
||||||
|
|
||||||
List<JpaRuntimeSearchParam> getActiveUniqueSearchParams(String theResourceName);
|
List<JpaRuntimeSearchParam> getActiveUniqueSearchParams(String theResourceName);
|
||||||
|
|
||||||
List<JpaRuntimeSearchParam> getActiveUniqueSearchParams(String theResourceName, Set<String> theParamNames);
|
void refreshCacheIfNecessary();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request that the cache be refreshed at the next convenient time (in a different thread)
|
||||||
|
*/
|
||||||
|
void requestRefresh();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
package ca.uhn.fhir.jpa.dao;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
|
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum.ResourceMetadataKeySupportingAnyResource;
|
||||||
|
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
||||||
|
public final class MetadataKeyCurrentlyReindexing extends ResourceMetadataKeySupportingAnyResource<Boolean, Boolean> {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
MetadataKeyCurrentlyReindexing(String theValue) {
|
||||||
|
super(theValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean get(IAnyResource theResource) {
|
||||||
|
return (Boolean) theResource.getUserData(IDao.CURRENTLY_REINDEXING.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean get(IResource theResource) {
|
||||||
|
return (Boolean) theResource.getResourceMetadata().get(IDao.CURRENTLY_REINDEXING);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean get(IBaseResource theResource) {
|
||||||
|
if (theResource instanceof IAnyResource) {
|
||||||
|
return get((IAnyResource) theResource);
|
||||||
|
} else {
|
||||||
|
return get((IResource) theResource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void put(IAnyResource theResource, Boolean theObject) {
|
||||||
|
theResource.setUserData(IDao.CURRENTLY_REINDEXING.name(), theObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(IBaseResource theResource, Boolean theValue) {
|
||||||
|
if (theResource instanceof IAnyResource) {
|
||||||
|
put((IAnyResource) theResource, theValue);
|
||||||
|
} else {
|
||||||
|
put((IResource) theResource, theValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void put(IResource theResource, Boolean theObject) {
|
||||||
|
theResource.getResourceMetadata().put(IDao.CURRENTLY_REINDEXING, theObject);
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,7 +28,7 @@ import ca.uhn.fhir.jpa.search.JpaRuntimeSearchParam;
|
||||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
||||||
import ca.uhn.fhir.jpa.term.VersionIndependentConcept;
|
import ca.uhn.fhir.jpa.term.VersionIndependentConcept;
|
||||||
import ca.uhn.fhir.jpa.util.BaseIterator;
|
import ca.uhn.fhir.jpa.util.BaseIterator;
|
||||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import ca.uhn.fhir.model.api.*;
|
import ca.uhn.fhir.model.api.*;
|
||||||
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
||||||
import ca.uhn.fhir.model.base.composite.BaseIdentifierDt;
|
import ca.uhn.fhir.model.base.composite.BaseIdentifierDt;
|
||||||
|
@ -83,7 +83,7 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
|
|
||||||
private static final List<Long> EMPTY_LONG_LIST = Collections.unmodifiableList(new ArrayList<Long>());
|
private static final List<Long> EMPTY_LONG_LIST = Collections.unmodifiableList(new ArrayList<Long>());
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchBuilder.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchBuilder.class);
|
||||||
private static Long NO_MORE = Long.valueOf(-1);
|
private static Long NO_MORE = -1L;
|
||||||
private static HandlerTypeEnum ourLastHandlerMechanismForUnitTest;
|
private static HandlerTypeEnum ourLastHandlerMechanismForUnitTest;
|
||||||
private List<Long> myAlsoIncludePids;
|
private List<Long> myAlsoIncludePids;
|
||||||
private CriteriaBuilder myBuilder;
|
private CriteriaBuilder myBuilder;
|
||||||
|
@ -331,10 +331,9 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
List<Predicate> codePredicates = new ArrayList<Predicate>();
|
List<Predicate> codePredicates = new ArrayList<Predicate>();
|
||||||
|
|
||||||
for (IQueryParameterType nextOr : theList) {
|
for (IQueryParameterType nextOr : theList) {
|
||||||
IQueryParameterType params = nextOr;
|
|
||||||
|
|
||||||
if (params instanceof ReferenceParam) {
|
if (nextOr instanceof ReferenceParam) {
|
||||||
ReferenceParam ref = (ReferenceParam) params;
|
ReferenceParam ref = (ReferenceParam) nextOr;
|
||||||
|
|
||||||
if (isBlank(ref.getChain())) {
|
if (isBlank(ref.getChain())) {
|
||||||
IIdType dt = new IdDt(ref.getBaseUrl(), ref.getResourceType(), ref.getIdPart(), null);
|
IIdType dt = new IdDt(ref.getBaseUrl(), ref.getResourceType(), ref.getIdPart(), null);
|
||||||
|
@ -471,7 +470,7 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
IQueryParameterType chainValue;
|
IQueryParameterType chainValue;
|
||||||
if (remainingChain != null) {
|
if (remainingChain != null) {
|
||||||
if (param == null || param.getParamType() != RestSearchParameterTypeEnum.REFERENCE) {
|
if (param == null || param.getParamType() != RestSearchParameterTypeEnum.REFERENCE) {
|
||||||
ourLog.debug("Type {} parameter {} is not a reference, can not chain {}", new Object[]{nextType.getSimpleName(), chain, remainingChain});
|
ourLog.debug("Type {} parameter {} is not a reference, can not chain {}", new Object[] {nextType.getSimpleName(), chain, remainingChain});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,7 +532,7 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Invalid token type (expecting ReferenceParam): " + params.getClass());
|
throw new IllegalArgumentException("Invalid token type (expecting ReferenceParam): " + nextOr.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -771,12 +770,11 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Predicate> codePredicates = new ArrayList<Predicate>();
|
List<Predicate> codePredicates = new ArrayList<>();
|
||||||
for (IQueryParameterType nextOr : theList) {
|
for (IQueryParameterType nextOr : theList) {
|
||||||
IQueryParameterType params = nextOr;
|
|
||||||
|
|
||||||
if (params instanceof UriParam) {
|
if (nextOr instanceof UriParam) {
|
||||||
UriParam param = (UriParam) params;
|
UriParam param = (UriParam) nextOr;
|
||||||
|
|
||||||
String value = param.getValue();
|
String value = param.getValue();
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
|
@ -821,7 +819,7 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
}
|
}
|
||||||
codePredicates.add(predicate);
|
codePredicates.add(predicate);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Invalid URI type: " + params.getClass());
|
throw new IllegalArgumentException("Invalid URI type: " + nextOr.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -838,9 +836,7 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
|
|
||||||
Predicate orPredicate = myBuilder.or(toArray(codePredicates));
|
Predicate orPredicate = myBuilder.or(toArray(codePredicates));
|
||||||
|
|
||||||
Predicate paramNamePredicate = myBuilder.equal(join.get("myParamName"), theParamName);
|
Predicate outerPredicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, join, orPredicate);
|
||||||
Predicate outerPredicate = myBuilder.and(paramNamePredicate, orPredicate);
|
|
||||||
|
|
||||||
myPredicates.add(outerPredicate);
|
myPredicates.add(outerPredicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1196,7 +1192,7 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
for (VersionIndependentConcept nextCode : codes) {
|
for (VersionIndependentConcept nextCode : codes) {
|
||||||
List<VersionIndependentConcept> systemCodes = map.get(nextCode.getSystem());
|
List<VersionIndependentConcept> systemCodes = map.get(nextCode.getSystem());
|
||||||
if (null == systemCodes) {
|
if (null == systemCodes) {
|
||||||
systemCodes = new ArrayList<VersionIndependentConcept>();
|
systemCodes = new ArrayList<>();
|
||||||
map.put(nextCode.getSystem(), systemCodes);
|
map.put(nextCode.getSystem(), systemCodes);
|
||||||
}
|
}
|
||||||
systemCodes.add(nextCode);
|
systemCodes.add(nextCode);
|
||||||
|
@ -1343,7 +1339,7 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
myPredicates = new ArrayList<Predicate>();
|
myPredicates = new ArrayList<>();
|
||||||
|
|
||||||
if (myParams.getEverythingMode() != null) {
|
if (myParams.getEverythingMode() != null) {
|
||||||
Join<ResourceTable, ResourceLink> join = myResourceTableRoot.join("myResourceLinks", JoinType.LEFT);
|
Join<ResourceTable, ResourceLink> join = myResourceTableRoot.join("myResourceLinks", JoinType.LEFT);
|
||||||
|
@ -1352,7 +1348,7 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
StringParam idParm = (StringParam) myParams.get(BaseResource.SP_RES_ID).get(0).get(0);
|
StringParam idParm = (StringParam) myParams.get(BaseResource.SP_RES_ID).get(0).get(0);
|
||||||
Long pid = BaseHapiFhirDao.translateForcedIdToPid(myResourceName, idParm.getValue(), myForcedIdDao);
|
Long pid = BaseHapiFhirDao.translateForcedIdToPid(myResourceName, idParm.getValue(), myForcedIdDao);
|
||||||
if (myAlsoIncludePids == null) {
|
if (myAlsoIncludePids == null) {
|
||||||
myAlsoIncludePids = new ArrayList<Long>(1);
|
myAlsoIncludePids = new ArrayList<>(1);
|
||||||
}
|
}
|
||||||
myAlsoIncludePids.add(pid);
|
myAlsoIncludePids.add(pid);
|
||||||
myPredicates.add(myBuilder.equal(join.get("myTargetResourcePid").as(Long.class), pid));
|
myPredicates.add(myBuilder.equal(join.get("myTargetResourcePid").as(Long.class), pid));
|
||||||
|
@ -1475,37 +1471,37 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
switch (param.getParamType()) {
|
switch (param.getParamType()) {
|
||||||
case STRING:
|
case STRING:
|
||||||
joinAttrName = "myParamsString";
|
joinAttrName = "myParamsString";
|
||||||
sortAttrName = new String[]{"myValueExact"};
|
sortAttrName = new String[] {"myValueExact"};
|
||||||
joinType = JoinEnum.STRING;
|
joinType = JoinEnum.STRING;
|
||||||
break;
|
break;
|
||||||
case DATE:
|
case DATE:
|
||||||
joinAttrName = "myParamsDate";
|
joinAttrName = "myParamsDate";
|
||||||
sortAttrName = new String[]{"myValueLow"};
|
sortAttrName = new String[] {"myValueLow"};
|
||||||
joinType = JoinEnum.DATE;
|
joinType = JoinEnum.DATE;
|
||||||
break;
|
break;
|
||||||
case REFERENCE:
|
case REFERENCE:
|
||||||
joinAttrName = "myResourceLinks";
|
joinAttrName = "myResourceLinks";
|
||||||
sortAttrName = new String[]{"myTargetResourcePid"};
|
sortAttrName = new String[] {"myTargetResourcePid"};
|
||||||
joinType = JoinEnum.REFERENCE;
|
joinType = JoinEnum.REFERENCE;
|
||||||
break;
|
break;
|
||||||
case TOKEN:
|
case TOKEN:
|
||||||
joinAttrName = "myParamsToken";
|
joinAttrName = "myParamsToken";
|
||||||
sortAttrName = new String[]{"mySystem", "myValue"};
|
sortAttrName = new String[] {"mySystem", "myValue"};
|
||||||
joinType = JoinEnum.TOKEN;
|
joinType = JoinEnum.TOKEN;
|
||||||
break;
|
break;
|
||||||
case NUMBER:
|
case NUMBER:
|
||||||
joinAttrName = "myParamsNumber";
|
joinAttrName = "myParamsNumber";
|
||||||
sortAttrName = new String[]{"myValue"};
|
sortAttrName = new String[] {"myValue"};
|
||||||
joinType = JoinEnum.NUMBER;
|
joinType = JoinEnum.NUMBER;
|
||||||
break;
|
break;
|
||||||
case URI:
|
case URI:
|
||||||
joinAttrName = "myParamsUri";
|
joinAttrName = "myParamsUri";
|
||||||
sortAttrName = new String[]{"myUri"};
|
sortAttrName = new String[] {"myUri"};
|
||||||
joinType = JoinEnum.URI;
|
joinType = JoinEnum.URI;
|
||||||
break;
|
break;
|
||||||
case QUANTITY:
|
case QUANTITY:
|
||||||
joinAttrName = "myParamsQuantity";
|
joinAttrName = "myParamsQuantity";
|
||||||
sortAttrName = new String[]{"myValue"};
|
sortAttrName = new String[] {"myValue"};
|
||||||
joinType = JoinEnum.QUANTITY;
|
joinType = JoinEnum.QUANTITY;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1780,7 +1776,7 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
nextRoundMatches = pidsToInclude;
|
nextRoundMatches = pidsToInclude;
|
||||||
} while (includes.size() > 0 && nextRoundMatches.size() > 0 && addedSomeThisRound);
|
} while (includes.size() > 0 && nextRoundMatches.size() > 0 && addedSomeThisRound);
|
||||||
|
|
||||||
ourLog.info("Loaded {} {} in {} rounds and {} ms", new Object[]{allAdded.size(), theReverseMode ? "_revincludes" : "_includes", roundCounts, w.getMillisAndRestart()});
|
ourLog.info("Loaded {} {} in {} rounds and {} ms", new Object[] {allAdded.size(), theReverseMode ? "_revincludes" : "_includes", roundCounts, w.getMillisAndRestart()});
|
||||||
|
|
||||||
return allAdded;
|
return allAdded;
|
||||||
}
|
}
|
||||||
|
@ -2006,8 +2002,17 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
RuntimeResourceDefinition resourceDef = theContext.getResourceDefinition(theResourceType);
|
RuntimeResourceDefinition resourceDef = theContext.getResourceDefinition(theResourceType);
|
||||||
RuntimeSearchParam param = theCallingDao.getSearchParamByName(resourceDef, theParamName);
|
RuntimeSearchParam param = theCallingDao.getSearchParamByName(resourceDef, theParamName);
|
||||||
List<String> path = param.getPathsSplit();
|
List<String> path = param.getPathsSplit();
|
||||||
Predicate type = theFrom.get("mySourcePath").in(path);
|
|
||||||
return type;
|
/*
|
||||||
|
* SearchParameters can declare paths on multiple resources
|
||||||
|
* types. Here we only want the ones that actually apply.
|
||||||
|
*/
|
||||||
|
for (Iterator<String> iter = path.iterator(); iter.hasNext(); ) {
|
||||||
|
if (!iter.next().startsWith(theResourceType + ".")) {
|
||||||
|
iter.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return theFrom.get("mySourcePath").in(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Long> filterResourceIdsByLastUpdated(EntityManager theEntityManager, final DateRangeParam theLastUpdated, Collection<Long> thePids) {
|
private static List<Long> filterResourceIdsByLastUpdated(EntityManager theEntityManager, final DateRangeParam theLastUpdated, Collection<Long> thePids) {
|
||||||
|
|
|
@ -21,17 +21,12 @@ package ca.uhn.fhir.jpa.dao;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.jpa.dao.dstu3.SearchParamRegistryDstu3;
|
|
||||||
import ca.uhn.fhir.jpa.search.JpaRuntimeSearchParam;
|
import ca.uhn.fhir.jpa.search.JpaRuntimeSearchParam;
|
||||||
import ca.uhn.fhir.jpa.util.JpaConstants;
|
import ca.uhn.fhir.jpa.util.JpaConstants;
|
||||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
|
||||||
import ca.uhn.fhir.model.api.ExtensionDt;
|
import ca.uhn.fhir.model.api.ExtensionDt;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.SearchParameter;
|
import ca.uhn.fhir.model.dstu2.resource.SearchParameter;
|
||||||
import ca.uhn.fhir.model.primitive.CodeDt;
|
|
||||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.util.DatatypeUtil;
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
@ -39,134 +34,19 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|
||||||
|
|
||||||
public class SearchParamRegistryDstu2 extends BaseSearchParamRegistry {
|
public class SearchParamRegistryDstu2 extends BaseSearchParamRegistry<SearchParameter> {
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParamRegistryDstu3.class);
|
|
||||||
public static final int MAX_MANAGED_PARAM_COUNT = 10000;
|
|
||||||
|
|
||||||
private volatile Map<String, Map<String, RuntimeSearchParam>> myActiveSearchParams;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private DaoConfig myDaoConfig;
|
|
||||||
|
|
||||||
private volatile long myLastRefresh;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IFhirResourceDao<SearchParameter> mySpDao;
|
private IFhirResourceDao<SearchParameter> mySpDao;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void forceRefresh() {
|
public IFhirResourceDao<SearchParameter> getSearchParameterDao() {
|
||||||
synchronized (this) {
|
return mySpDao;
|
||||||
myLastRefresh = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Map<String, RuntimeSearchParam>> getActiveSearchParams() {
|
protected JpaRuntimeSearchParam toRuntimeSp(SearchParameter theNextSp) {
|
||||||
refreshCacheIfNecessary();
|
|
||||||
return myActiveSearchParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, RuntimeSearchParam> getActiveSearchParams(String theResourceName) {
|
|
||||||
refreshCacheIfNecessary();
|
|
||||||
return myActiveSearchParams.get(theResourceName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, RuntimeSearchParam> getSearchParamMap(Map<String, Map<String, RuntimeSearchParam>> searchParams, String theResourceName) {
|
|
||||||
Map<String, RuntimeSearchParam> retVal = searchParams.get(theResourceName);
|
|
||||||
if (retVal == null) {
|
|
||||||
retVal = new HashMap<>();
|
|
||||||
searchParams.put(theResourceName, retVal);
|
|
||||||
}
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void refreshCacheIfNecessary() {
|
|
||||||
long refreshInterval = 60 * DateUtils.MILLIS_PER_MINUTE;
|
|
||||||
if (System.currentTimeMillis() - refreshInterval > myLastRefresh) {
|
|
||||||
synchronized (this) {
|
|
||||||
if (System.currentTimeMillis() - refreshInterval > myLastRefresh) {
|
|
||||||
StopWatch sw = new StopWatch();
|
|
||||||
|
|
||||||
Map<String, Map<String, RuntimeSearchParam>> searchParams = new HashMap<>();
|
|
||||||
for (Map.Entry<String, Map<String, RuntimeSearchParam>> nextBuiltInEntry : getBuiltInSearchParams().entrySet()) {
|
|
||||||
for (RuntimeSearchParam nextParam : nextBuiltInEntry.getValue().values()) {
|
|
||||||
String nextResourceName = nextBuiltInEntry.getKey();
|
|
||||||
getSearchParamMap(searchParams, nextResourceName).put(nextParam.getName(), nextParam);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchParameterMap params = new SearchParameterMap();
|
|
||||||
params.setLoadSynchronousUpTo(MAX_MANAGED_PARAM_COUNT);
|
|
||||||
|
|
||||||
IBundleProvider allSearchParamsBp = mySpDao.search(params);
|
|
||||||
int size = allSearchParamsBp.size();
|
|
||||||
|
|
||||||
// Just in case..
|
|
||||||
if (size > MAX_MANAGED_PARAM_COUNT) {
|
|
||||||
ourLog.warn("Unable to support >" + MAX_MANAGED_PARAM_COUNT + " search params!");
|
|
||||||
size = MAX_MANAGED_PARAM_COUNT;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<IBaseResource> allSearchParams = allSearchParamsBp.getResources(0, size);
|
|
||||||
for (IBaseResource nextResource : allSearchParams) {
|
|
||||||
SearchParameter nextSp = (SearchParameter) nextResource;
|
|
||||||
JpaRuntimeSearchParam runtimeSp = toRuntimeSp(nextSp);
|
|
||||||
if (runtimeSp == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
CodeDt nextBaseName = nextSp.getBaseElement();
|
|
||||||
String resourceType = nextBaseName.getValue();
|
|
||||||
if (isBlank(resourceType)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, RuntimeSearchParam> searchParamMap = getSearchParamMap(searchParams, resourceType);
|
|
||||||
String name = runtimeSp.getName();
|
|
||||||
if (myDaoConfig.isDefaultSearchParamsCanBeOverridden() || !searchParamMap.containsKey(name)) {
|
|
||||||
searchParamMap.put(name, runtimeSp);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, Map<String, RuntimeSearchParam>> activeSearchParams = new HashMap<>();
|
|
||||||
for (Map.Entry<String, Map<String, RuntimeSearchParam>> nextEntry : searchParams.entrySet()) {
|
|
||||||
for (RuntimeSearchParam nextSp : nextEntry.getValue().values()) {
|
|
||||||
String nextName = nextSp.getName();
|
|
||||||
if (nextSp.getStatus() != RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE) {
|
|
||||||
nextSp = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!activeSearchParams.containsKey(nextEntry.getKey())) {
|
|
||||||
activeSearchParams.put(nextEntry.getKey(), new HashMap<String, RuntimeSearchParam>());
|
|
||||||
}
|
|
||||||
if (activeSearchParams.containsKey(nextEntry.getKey())) {
|
|
||||||
ourLog.debug("Replacing existing/built in search param {}:{} with new one", nextEntry.getKey(), nextName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextSp != null) {
|
|
||||||
activeSearchParams.get(nextEntry.getKey()).put(nextName, nextSp);
|
|
||||||
} else {
|
|
||||||
activeSearchParams.get(nextEntry.getKey()).remove(nextName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
myActiveSearchParams = activeSearchParams;
|
|
||||||
|
|
||||||
super.populateActiveSearchParams(activeSearchParams);
|
|
||||||
|
|
||||||
myLastRefresh = System.currentTimeMillis();
|
|
||||||
ourLog.info("Refreshed search parameter cache in {}ms", sw.getMillis());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private JpaRuntimeSearchParam toRuntimeSp(SearchParameter theNextSp) {
|
|
||||||
String name = theNextSp.getCode();
|
String name = theNextSp.getCode();
|
||||||
String description = theNextSp.getDescription();
|
String description = theNextSp.getDescription();
|
||||||
String path = theNextSp.getXpath();
|
String path = theNextSp.getXpath();
|
||||||
|
@ -212,9 +92,9 @@ public class SearchParamRegistryDstu2 extends BaseSearchParamRegistry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Set<String> providesMembershipInCompartments = Collections.emptySet();
|
Set<String> providesMembershipInCompartments = Collections.emptySet();
|
||||||
Set<String> targets = toStrings(theNextSp.getTarget());
|
Set<String> targets = DatatypeUtil.toStringSet(theNextSp.getTarget());
|
||||||
|
|
||||||
if (isBlank(name) || isBlank(path) || paramType == null) {
|
if (isBlank(name) || isBlank(path)) {
|
||||||
if (paramType != RestSearchParameterTypeEnum.COMPOSITE) {
|
if (paramType != RestSearchParameterTypeEnum.COMPOSITE) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -235,19 +115,8 @@ public class SearchParamRegistryDstu2 extends BaseSearchParamRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<JpaRuntimeSearchParam.Component> components = Collections.emptyList();
|
List<JpaRuntimeSearchParam.Component> components = Collections.emptyList();
|
||||||
Collection<? extends IPrimitiveType<String>> base = Arrays.asList(theNextSp.getBaseElement());
|
Collection<? extends IPrimitiveType<String>> base = Collections.singletonList(theNextSp.getBaseElement());
|
||||||
JpaRuntimeSearchParam retVal = new JpaRuntimeSearchParam(id, uri, name, description, path, paramType, providesMembershipInCompartments, targets, status, unique, components, base);
|
return new JpaRuntimeSearchParam(id, uri, name, description, path, paramType, providesMembershipInCompartments, targets, status, unique, components, base);
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<String> toStrings(List<? extends CodeDt> theTarget) {
|
|
||||||
HashSet<String> retVal = new HashSet<String>();
|
|
||||||
for (CodeDt next : theTarget) {
|
|
||||||
if (isNotBlank(next.getValue())) {
|
|
||||||
retVal.add(next.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return retVal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,9 @@ public class FhirResourceDaoSearchParameterDstu3 extends FhirResourceDaoDstu3<Se
|
||||||
private IFhirSystemDao<Bundle, Meta> mySystemDao;
|
private IFhirSystemDao<Bundle, Meta> mySystemDao;
|
||||||
|
|
||||||
protected void markAffectedResources(SearchParameter theResource) {
|
protected void markAffectedResources(SearchParameter theResource) {
|
||||||
markResourcesMatchingExpressionAsNeedingReindexing(theResource != null ? theResource.getExpression() : null);
|
Boolean reindex = theResource != null ? CURRENTLY_REINDEXING.get(theResource) : null;
|
||||||
|
String expression = theResource != null ? theResource.getExpression() : null;
|
||||||
|
markResourcesMatchingExpressionAsNeedingReindexing(reindex, expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -29,6 +29,7 @@ import ca.uhn.fhir.jpa.entity.SubscriptionTable;
|
||||||
import ca.uhn.fhir.parser.DataFormatException;
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.hl7.fhir.dstu3.model.Subscription;
|
import org.hl7.fhir.dstu3.model.Subscription;
|
||||||
import org.hl7.fhir.dstu3.model.Subscription.SubscriptionChannelType;
|
import org.hl7.fhir.dstu3.model.Subscription.SubscriptionChannelType;
|
||||||
import org.hl7.fhir.dstu3.model.Subscription.SubscriptionStatus;
|
import org.hl7.fhir.dstu3.model.Subscription.SubscriptionStatus;
|
||||||
|
@ -108,6 +109,16 @@ public class FhirResourceDaoSubscriptionDstu3 extends FhirResourceDaoDstu3<Subsc
|
||||||
}
|
}
|
||||||
|
|
||||||
public RuntimeResourceDefinition validateCriteriaAndReturnResourceDefinition(Subscription theResource) {
|
public RuntimeResourceDefinition validateCriteriaAndReturnResourceDefinition(Subscription theResource) {
|
||||||
|
switch (ObjectUtils.defaultIfNull(theResource.getStatus(), SubscriptionStatus.OFF)) {
|
||||||
|
case REQUESTED:
|
||||||
|
case ACTIVE:
|
||||||
|
break;
|
||||||
|
case ERROR:
|
||||||
|
case OFF:
|
||||||
|
case NULL:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
String query = theResource.getCriteria();
|
String query = theResource.getCriteria();
|
||||||
if (isBlank(query)) {
|
if (isBlank(query)) {
|
||||||
throw new UnprocessableEntityException("Subscription.criteria must be populated");
|
throw new UnprocessableEntityException("Subscription.criteria must be populated");
|
||||||
|
@ -144,6 +155,9 @@ public class FhirResourceDaoSubscriptionDstu3 extends FhirResourceDaoDstu3<Subsc
|
||||||
super.validateResourceForStorage(theResource, theEntityToSave);
|
super.validateResourceForStorage(theResource, theEntityToSave);
|
||||||
|
|
||||||
RuntimeResourceDefinition resDef = validateCriteriaAndReturnResourceDefinition(theResource);
|
RuntimeResourceDefinition resDef = validateCriteriaAndReturnResourceDefinition(theResource);
|
||||||
|
if (resDef == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
IFhirResourceDao<? extends IBaseResource> dao = getDao(resDef.getImplementingClass());
|
IFhirResourceDao<? extends IBaseResource> dao = getDao(resDef.getImplementingClass());
|
||||||
if (dao == null) {
|
if (dao == null) {
|
||||||
|
|
|
@ -28,7 +28,7 @@ import java.util.Map.Entry;
|
||||||
|
|
||||||
import javax.persistence.TypedQuery;
|
import javax.persistence.TypedQuery;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import ca.uhn.fhir.rest.param.ParameterUtil;
|
import ca.uhn.fhir.rest.param.ParameterUtil;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.apache.http.NameValuePair;
|
import org.apache.http.NameValuePair;
|
||||||
|
@ -260,7 +260,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
}
|
}
|
||||||
for (java.util.Map.Entry<String, Collection<String>> nextParamEntry : paramValues.asMap().entrySet()) {
|
for (java.util.Map.Entry<String, Collection<String>> nextParamEntry : paramValues.asMap().entrySet()) {
|
||||||
String[] nextValue = nextParamEntry.getValue().toArray(new String[nextParamEntry.getValue().size()]);
|
String[] nextValue = nextParamEntry.getValue().toArray(new String[nextParamEntry.getValue().size()]);
|
||||||
requestDetails.getParameters().put(nextParamEntry.getKey(), nextValue);
|
requestDetails.addParameter(nextParamEntry.getKey(), nextValue);
|
||||||
}
|
}
|
||||||
url = url.substring(0, qIndex);
|
url = url.substring(0, qIndex);
|
||||||
}
|
}
|
||||||
|
@ -311,7 +311,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private Map<BundleEntryComponent, ResourceTable> doTransactionWriteOperations(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName, Date updateTime, Set<IdType> allIds,
|
private Map<BundleEntryComponent, ResourceTable> doTransactionWriteOperations(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName, Date updateTime, Set<IdType> allIds,
|
||||||
Map<IdType, IdType> idSubstitutions, Map<IdType, DaoMethodOutcome> idToPersistedOutcome, Bundle response, IdentityHashMap<BundleEntryComponent, Integer> originalRequestOrder, List<BundleEntryComponent> theEntries) {
|
Map<IdType, IdType> theIdSubstitutions, Map<IdType, DaoMethodOutcome> idToPersistedOutcome, Bundle response, IdentityHashMap<BundleEntryComponent, Integer> originalRequestOrder, List<BundleEntryComponent> theEntries) {
|
||||||
Set<String> deletedResources = new HashSet<String>();
|
Set<String> deletedResources = new HashSet<String>();
|
||||||
List<DeleteConflict> deleteConflicts = new ArrayList<DeleteConflict>();
|
List<DeleteConflict> deleteConflicts = new ArrayList<DeleteConflict>();
|
||||||
Map<BundleEntryComponent, ResourceTable> entriesToProcess = new IdentityHashMap<BundleEntryComponent, ResourceTable>();
|
Map<BundleEntryComponent, ResourceTable> entriesToProcess = new IdentityHashMap<BundleEntryComponent, ResourceTable>();
|
||||||
|
@ -379,10 +379,10 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
res.setId((String) null);
|
res.setId((String) null);
|
||||||
DaoMethodOutcome outcome;
|
DaoMethodOutcome outcome;
|
||||||
String matchUrl = nextReqEntry.getRequest().getIfNoneExist();
|
String matchUrl = nextReqEntry.getRequest().getIfNoneExist();
|
||||||
matchUrl = performIdSubstitutionsInMatchUrl(idSubstitutions, matchUrl);
|
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
||||||
outcome = resourceDao.create(res, matchUrl, false, theRequestDetails);
|
outcome = resourceDao.create(res, matchUrl, false, theRequestDetails);
|
||||||
if (nextResourceId != null) {
|
if (nextResourceId != null) {
|
||||||
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
||||||
}
|
}
|
||||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||||
if (outcome.getCreated() == false) {
|
if (outcome.getCreated() == false) {
|
||||||
|
@ -412,7 +412,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
String matchUrl = parts.getResourceType() + '?' + parts.getParams();
|
String matchUrl = parts.getResourceType() + '?' + parts.getParams();
|
||||||
matchUrl = performIdSubstitutionsInMatchUrl(idSubstitutions, matchUrl);
|
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
||||||
DeleteMethodOutcome deleteOutcome = dao.deleteByUrl(matchUrl, deleteConflicts, theRequestDetails);
|
DeleteMethodOutcome deleteOutcome = dao.deleteByUrl(matchUrl, deleteConflicts, theRequestDetails);
|
||||||
List<ResourceTable> allDeleted = deleteOutcome.getDeletedEntities();
|
List<ResourceTable> allDeleted = deleteOutcome.getDeletedEntities();
|
||||||
for (ResourceTable deleted : allDeleted) {
|
for (ResourceTable deleted : allDeleted) {
|
||||||
|
@ -453,14 +453,14 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
} else {
|
} else {
|
||||||
matchUrl = parts.getResourceType();
|
matchUrl = parts.getResourceType();
|
||||||
}
|
}
|
||||||
matchUrl = performIdSubstitutionsInMatchUrl(idSubstitutions, matchUrl);
|
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
||||||
outcome = resourceDao.update(res, matchUrl, false, theRequestDetails);
|
outcome = resourceDao.update(res, matchUrl, false, theRequestDetails);
|
||||||
if (Boolean.TRUE.equals(outcome.getCreated())) {
|
if (Boolean.TRUE.equals(outcome.getCreated())) {
|
||||||
conditionalRequestUrls.put(matchUrl, res.getClass());
|
conditionalRequestUrls.put(matchUrl, res.getClass());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
||||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -496,15 +496,16 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Refererences
|
||||||
List<IBaseReference> allRefs = terser.getAllPopulatedChildElementsOfType(nextResource, IBaseReference.class);
|
List<IBaseReference> allRefs = terser.getAllPopulatedChildElementsOfType(nextResource, IBaseReference.class);
|
||||||
for (IBaseReference nextRef : allRefs) {
|
for (IBaseReference nextRef : allRefs) {
|
||||||
IIdType nextId = nextRef.getReferenceElement();
|
IIdType nextId = nextRef.getReferenceElement();
|
||||||
if (!nextId.hasIdPart()) {
|
if (!nextId.hasIdPart()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (idSubstitutions.containsKey(nextId)) {
|
if (theIdSubstitutions.containsKey(nextId)) {
|
||||||
IdType newId = idSubstitutions.get(nextId);
|
IdType newId = theIdSubstitutions.get(nextId);
|
||||||
ourLog.info(" * Replacing resource ref {} with {}", nextId, newId);
|
ourLog.debug(" * Replacing resource ref {} with {}", nextId, newId);
|
||||||
nextRef.setReference(newId.getValue());
|
nextRef.setReference(newId.getValue());
|
||||||
} else if (nextId.getValue().startsWith("urn:")) {
|
} else if (nextId.getValue().startsWith("urn:")) {
|
||||||
throw new InvalidRequestException("Unable to satisfy placeholder ID: " + nextId.getValue());
|
throw new InvalidRequestException("Unable to satisfy placeholder ID: " + nextId.getValue());
|
||||||
|
@ -513,6 +514,22 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// URIs
|
||||||
|
List<UriType> allUris = terser.getAllPopulatedChildElementsOfType(nextResource, UriType.class);
|
||||||
|
for (UriType nextRef : allUris) {
|
||||||
|
if (nextRef instanceof IIdType) {
|
||||||
|
continue; // No substitution on the resource ID itself!
|
||||||
|
}
|
||||||
|
IdType nextUriString = new IdType(nextRef.getValueAsString());
|
||||||
|
if (theIdSubstitutions.containsKey(nextUriString)) {
|
||||||
|
IdType newId = theIdSubstitutions.get(nextUriString);
|
||||||
|
ourLog.debug(" * Replacing resource ref {} with {}", nextUriString, newId);
|
||||||
|
nextRef.setValue(newId.getValue());
|
||||||
|
} else {
|
||||||
|
ourLog.debug(" * Reference [{}] does not exist in bundle", nextUriString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IPrimitiveType<Date> deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get((IAnyResource) nextResource);
|
IPrimitiveType<Date> deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get((IAnyResource) nextResource);
|
||||||
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
||||||
boolean shouldUpdate = !nonUpdatedEntities.contains(nextOutcome.getEntity());
|
boolean shouldUpdate = !nonUpdatedEntities.contains(nextOutcome.getEntity());
|
||||||
|
@ -521,13 +538,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionImpl session = (SessionImpl) myEntityManager.unwrap(Session.class);
|
flushJpaSession();
|
||||||
int insertionCount = session.getActionQueue().numberOfInsertions();
|
|
||||||
int updateCount = session.getActionQueue().numberOfUpdates();
|
|
||||||
|
|
||||||
StopWatch sw = new StopWatch();
|
|
||||||
myEntityManager.flush();
|
|
||||||
ourLog.info("Session flush took {}ms for {} inserts and {} updates", sw.getMillis(), insertionCount, updateCount);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Double check we didn't allow any duplicates we shouldn't have
|
* Double check we didn't allow any duplicates we shouldn't have
|
||||||
|
@ -546,14 +557,14 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (IdType next : allIds) {
|
for (IdType next : allIds) {
|
||||||
IdType replacement = idSubstitutions.get(next);
|
IdType replacement = theIdSubstitutions.get(next);
|
||||||
if (replacement == null) {
|
if (replacement == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (replacement.equals(next)) {
|
if (replacement.equals(next)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ourLog.info("Placeholder resource ID \"{}\" was replaced with permanent ID \"{}\"", next, replacement);
|
ourLog.debug("Placeholder resource ID \"{}\" was replaced with permanent ID \"{}\"", next, replacement);
|
||||||
}
|
}
|
||||||
return entriesToProcess;
|
return entriesToProcess;
|
||||||
}
|
}
|
||||||
|
@ -603,6 +614,23 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String performIdSubstitutionsInMatchUrl(Map<IdType, IdType> theIdSubstitutions, String theMatchUrl) {
|
||||||
|
String matchUrl = theMatchUrl;
|
||||||
|
if (isNotBlank(matchUrl)) {
|
||||||
|
for (Entry<IdType, IdType> nextSubstitutionEntry : theIdSubstitutions.entrySet()) {
|
||||||
|
IdType nextTemporaryId = nextSubstitutionEntry.getKey();
|
||||||
|
IdType nextReplacementId = nextSubstitutionEntry.getValue();
|
||||||
|
String nextTemporaryIdPart = nextTemporaryId.getIdPart();
|
||||||
|
String nextReplacementIdPart = nextReplacementId.getValueAsString();
|
||||||
|
if (nextTemporaryId.isUrn() && nextTemporaryIdPart.length() > IdType.URN_PREFIX.length()) {
|
||||||
|
matchUrl = matchUrl.replace(nextTemporaryIdPart, nextReplacementIdPart);
|
||||||
|
matchUrl = matchUrl.replace(UrlUtil.escapeUrlParam(nextTemporaryIdPart), nextReplacementIdPart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return matchUrl;
|
||||||
|
}
|
||||||
|
|
||||||
private void populateEntryWithOperationOutcome(BaseServerResponseException caughtEx, BundleEntryComponent nextEntry) {
|
private void populateEntryWithOperationOutcome(BaseServerResponseException caughtEx, BundleEntryComponent nextEntry) {
|
||||||
OperationOutcome oo = new OperationOutcome();
|
OperationOutcome oo = new OperationOutcome();
|
||||||
oo.addIssue().setSeverity(IssueSeverity.ERROR).setDiagnostics(caughtEx.getMessage());
|
oo.addIssue().setSeverity(IssueSeverity.ERROR).setDiagnostics(caughtEx.getMessage());
|
||||||
|
@ -664,27 +692,6 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
return transaction((ServletRequestDetails) theRequestDetails, theRequest, actionName);
|
return transaction((ServletRequestDetails) theRequestDetails, theRequest, actionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private String performIdSubstitutionsInMatchUrl(Map<IdType, IdType> theIdSubstitutions, String theMatchUrl) {
|
|
||||||
String matchUrl = theMatchUrl;
|
|
||||||
if (isNotBlank(matchUrl)) {
|
|
||||||
for (Entry<IdType, IdType> nextSubstitutionEntry : theIdSubstitutions.entrySet()) {
|
|
||||||
IdType nextTemporaryId = nextSubstitutionEntry.getKey();
|
|
||||||
IdType nextReplacementId = nextSubstitutionEntry.getValue();
|
|
||||||
String nextTemporaryIdPart = nextTemporaryId.getIdPart();
|
|
||||||
String nextReplacementIdPart = nextReplacementId.getValueAsString();
|
|
||||||
if (nextTemporaryId.isUrn() && nextTemporaryIdPart.length() > IdType.URN_PREFIX.length()) {
|
|
||||||
matchUrl = matchUrl.replace(nextTemporaryIdPart, nextReplacementIdPart);
|
|
||||||
matchUrl = matchUrl.replace(UrlUtil.escapeUrlParam(nextTemporaryIdPart), nextReplacementIdPart);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return matchUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private Bundle transaction(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName) {
|
private Bundle transaction(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName) {
|
||||||
super.markRequestAsProcessingSubRequest(theRequestDetails);
|
super.markRequestAsProcessingSubRequest(theRequestDetails);
|
||||||
try {
|
try {
|
||||||
|
@ -742,23 +749,9 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
return Integer.toString(theStatusCode) + " " + defaultString(Constants.HTTP_STATUS_NAMES.get(theStatusCode));
|
return Integer.toString(theStatusCode) + " " + defaultString(Constants.HTTP_STATUS_NAMES.get(theStatusCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class BaseServerResponseExceptionHolder
|
|
||||||
{
|
|
||||||
private BaseServerResponseException myException;
|
|
||||||
|
|
||||||
public BaseServerResponseException getException() {
|
|
||||||
return myException;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setException(BaseServerResponseException myException) {
|
|
||||||
this.myException = myException;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//@formatter:off
|
|
||||||
/**
|
/**
|
||||||
* Transaction Order, per the spec:
|
* Transaction Order, per the spec:
|
||||||
*
|
*
|
||||||
* Process any DELETE interactions
|
* Process any DELETE interactions
|
||||||
* Process any POST interactions
|
* Process any POST interactions
|
||||||
* Process any PUT interactions
|
* Process any PUT interactions
|
||||||
|
@ -859,4 +852,19 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
|
||||||
|
private static class BaseServerResponseExceptionHolder
|
||||||
|
{
|
||||||
|
private BaseServerResponseException myException;
|
||||||
|
|
||||||
|
public BaseServerResponseException getException() {
|
||||||
|
return myException;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setException(BaseServerResponseException myException) {
|
||||||
|
this.myException = myException;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.dao.dstu3;
|
||||||
*/
|
*/
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
import static org.apache.commons.lang3.StringUtils.trim;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
@ -478,8 +479,8 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
|
||||||
multiType = true;
|
multiType = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> systems = new ArrayList<String>();
|
List<String> systems = new ArrayList<>();
|
||||||
List<String> codes = new ArrayList<String>();
|
List<String> codes = new ArrayList<>();
|
||||||
|
|
||||||
// String needContactPointSystem = null;
|
// String needContactPointSystem = null;
|
||||||
// if (nextPath.contains(".where(system='phone')")) {
|
// if (nextPath.contains(".where(system='phone')")) {
|
||||||
|
@ -693,11 +694,11 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
|
||||||
IWorkerContext worker = new org.hl7.fhir.dstu3.hapi.ctx.HapiWorkerContext(getContext(), myValidationSupport);
|
IWorkerContext worker = new org.hl7.fhir.dstu3.hapi.ctx.HapiWorkerContext(getContext(), myValidationSupport);
|
||||||
FHIRPathEngine fp = new FHIRPathEngine(worker);
|
FHIRPathEngine fp = new FHIRPathEngine(worker);
|
||||||
|
|
||||||
List<Object> values = new ArrayList<Object>();
|
List<Object> values = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
String[] nextPathsSplit = SPLIT.split(thePaths);
|
String[] nextPathsSplit = SPLIT.split(thePaths);
|
||||||
for (String nextPath : nextPathsSplit) {
|
for (String nextPath : nextPathsSplit) {
|
||||||
List<Base> allValues = fp.evaluate((Base) theResource, nextPath);
|
List<Base> allValues = fp.evaluate((Base) theResource, trim(nextPath));
|
||||||
if (allValues.isEmpty() == false) {
|
if (allValues.isEmpty() == false) {
|
||||||
values.addAll(allValues);
|
values.addAll(allValues);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,210 +20,91 @@ package ca.uhn.fhir.jpa.dao.dstu3;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import ca.uhn.fhir.context.RuntimeSearchParam.RuntimeSearchParamStatusEnum;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import ca.uhn.fhir.jpa.dao.BaseSearchParamRegistry;
|
||||||
|
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||||
import java.util.*;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.search.JpaRuntimeSearchParam;
|
import ca.uhn.fhir.jpa.search.JpaRuntimeSearchParam;
|
||||||
import ca.uhn.fhir.jpa.util.JpaConstants;
|
import ca.uhn.fhir.jpa.util.JpaConstants;
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||||
import org.hl7.fhir.dstu3.model.CodeType;
|
import ca.uhn.fhir.util.DatatypeUtil;
|
||||||
import org.hl7.fhir.dstu3.model.Extension;
|
import org.hl7.fhir.dstu3.model.Extension;
|
||||||
import org.hl7.fhir.dstu3.model.SearchParameter;
|
import org.hl7.fhir.dstu3.model.SearchParameter;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
import java.util.ArrayList;
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam.RuntimeSearchParamStatusEnum;
|
import java.util.Collections;
|
||||||
import ca.uhn.fhir.jpa.dao.*;
|
import java.util.List;
|
||||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
import java.util.Set;
|
||||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
|
||||||
|
|
||||||
public class SearchParamRegistryDstu3 extends BaseSearchParamRegistry {
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParamRegistryDstu3.class);
|
|
||||||
public static final int MAX_MANAGED_PARAM_COUNT = 10000;
|
|
||||||
|
|
||||||
private volatile Map<String, Map<String, RuntimeSearchParam>> myActiveSearchParams;
|
public class SearchParamRegistryDstu3 extends BaseSearchParamRegistry<SearchParameter> {
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private DaoConfig myDaoConfig;
|
|
||||||
|
|
||||||
private volatile long myLastRefresh;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IFhirResourceDao<SearchParameter> mySpDao;
|
private IFhirResourceDao<SearchParameter> mySpDao;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void forceRefresh() {
|
public IFhirResourceDao<SearchParameter> getSearchParameterDao() {
|
||||||
synchronized (this) {
|
return mySpDao;
|
||||||
myLastRefresh = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Map<String, RuntimeSearchParam>> getActiveSearchParams() {
|
protected JpaRuntimeSearchParam toRuntimeSp(SearchParameter theNextSp) {
|
||||||
refreshCacheIfNecessary();
|
|
||||||
return myActiveSearchParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, RuntimeSearchParam> getActiveSearchParams(String theResourceName) {
|
|
||||||
refreshCacheIfNecessary();
|
|
||||||
return myActiveSearchParams.get(theResourceName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, RuntimeSearchParam> getSearchParamMap(Map<String, Map<String, RuntimeSearchParam>> searchParams, String theResourceName) {
|
|
||||||
Map<String, RuntimeSearchParam> retVal = searchParams.get(theResourceName);
|
|
||||||
if (retVal == null) {
|
|
||||||
retVal = new HashMap<>();
|
|
||||||
searchParams.put(theResourceName, retVal);
|
|
||||||
}
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void refreshCacheIfNecessary() {
|
|
||||||
long refreshInterval = 60 * DateUtils.MILLIS_PER_MINUTE;
|
|
||||||
if (System.currentTimeMillis() - refreshInterval > myLastRefresh) {
|
|
||||||
synchronized (this) {
|
|
||||||
if (System.currentTimeMillis() - refreshInterval > myLastRefresh) {
|
|
||||||
StopWatch sw = new StopWatch();
|
|
||||||
|
|
||||||
Map<String, Map<String, RuntimeSearchParam>> searchParams = new HashMap<>();
|
|
||||||
for (Entry<String, Map<String, RuntimeSearchParam>> nextBuiltInEntry : getBuiltInSearchParams().entrySet()) {
|
|
||||||
for (RuntimeSearchParam nextParam : nextBuiltInEntry.getValue().values()) {
|
|
||||||
String nextResourceName = nextBuiltInEntry.getKey();
|
|
||||||
getSearchParamMap(searchParams, nextResourceName).put(nextParam.getName(), nextParam);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchParameterMap params = new SearchParameterMap();
|
|
||||||
params.setLoadSynchronousUpTo(MAX_MANAGED_PARAM_COUNT);
|
|
||||||
|
|
||||||
IBundleProvider allSearchParamsBp = mySpDao.search(params);
|
|
||||||
int size = allSearchParamsBp.size();
|
|
||||||
|
|
||||||
// Just in case..
|
|
||||||
if (size > MAX_MANAGED_PARAM_COUNT) {
|
|
||||||
ourLog.warn("Unable to support >" + MAX_MANAGED_PARAM_COUNT + " search params!");
|
|
||||||
size = MAX_MANAGED_PARAM_COUNT;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<IBaseResource> allSearchParams = allSearchParamsBp.getResources(0, size);
|
|
||||||
for (IBaseResource nextResource : allSearchParams) {
|
|
||||||
SearchParameter nextSp = (SearchParameter) nextResource;
|
|
||||||
JpaRuntimeSearchParam runtimeSp = toRuntimeSp(nextSp);
|
|
||||||
if (runtimeSp == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (org.hl7.fhir.dstu3.model.CodeType nextBaseName : nextSp.getBase()) {
|
|
||||||
String resourceType = nextBaseName.getValue();
|
|
||||||
if (isBlank(resourceType)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, RuntimeSearchParam> searchParamMap = getSearchParamMap(searchParams, resourceType);
|
|
||||||
String name = runtimeSp.getName();
|
|
||||||
if (myDaoConfig.isDefaultSearchParamsCanBeOverridden() || !searchParamMap.containsKey(name)) {
|
|
||||||
searchParamMap.put(name, runtimeSp);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, Map<String, RuntimeSearchParam>> activeSearchParams = new HashMap<>();
|
|
||||||
for (Entry<String, Map<String, RuntimeSearchParam>> nextEntry : searchParams.entrySet()) {
|
|
||||||
for (RuntimeSearchParam nextSp : nextEntry.getValue().values()) {
|
|
||||||
String nextName = nextSp.getName();
|
|
||||||
if (nextSp.getStatus() != RuntimeSearchParamStatusEnum.ACTIVE) {
|
|
||||||
nextSp = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!activeSearchParams.containsKey(nextEntry.getKey())) {
|
|
||||||
activeSearchParams.put(nextEntry.getKey(), new HashMap<String, RuntimeSearchParam>());
|
|
||||||
}
|
|
||||||
if (activeSearchParams.containsKey(nextEntry.getKey())) {
|
|
||||||
ourLog.debug("Replacing existing/built in search param {}:{} with new one", nextEntry.getKey(), nextName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextSp != null) {
|
|
||||||
activeSearchParams.get(nextEntry.getKey()).put(nextName, nextSp);
|
|
||||||
} else {
|
|
||||||
activeSearchParams.get(nextEntry.getKey()).remove(nextName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
myActiveSearchParams = activeSearchParams;
|
|
||||||
|
|
||||||
super.populateActiveSearchParams(activeSearchParams);
|
|
||||||
|
|
||||||
myLastRefresh = System.currentTimeMillis();
|
|
||||||
ourLog.info("Refreshed search parameter cache in {}ms", sw.getMillis());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private JpaRuntimeSearchParam toRuntimeSp(SearchParameter theNextSp) {
|
|
||||||
String name = theNextSp.getCode();
|
String name = theNextSp.getCode();
|
||||||
String description = theNextSp.getDescription();
|
String description = theNextSp.getDescription();
|
||||||
String path = theNextSp.getExpression();
|
String path = theNextSp.getExpression();
|
||||||
RestSearchParameterTypeEnum paramType = null;
|
RestSearchParameterTypeEnum paramType = null;
|
||||||
RuntimeSearchParamStatusEnum status = null;
|
RuntimeSearchParamStatusEnum status = null;
|
||||||
switch (theNextSp.getType()) {
|
switch (theNextSp.getType()) {
|
||||||
case COMPOSITE:
|
case COMPOSITE:
|
||||||
paramType = RestSearchParameterTypeEnum.COMPOSITE;
|
paramType = RestSearchParameterTypeEnum.COMPOSITE;
|
||||||
break;
|
|
||||||
case DATE:
|
|
||||||
paramType = RestSearchParameterTypeEnum.DATE;
|
|
||||||
break;
|
|
||||||
case NUMBER:
|
|
||||||
paramType = RestSearchParameterTypeEnum.NUMBER;
|
|
||||||
break;
|
|
||||||
case QUANTITY:
|
|
||||||
paramType = RestSearchParameterTypeEnum.QUANTITY;
|
|
||||||
break;
|
|
||||||
case REFERENCE:
|
|
||||||
paramType = RestSearchParameterTypeEnum.REFERENCE;
|
|
||||||
break;
|
|
||||||
case STRING:
|
|
||||||
paramType = RestSearchParameterTypeEnum.STRING;
|
|
||||||
break;
|
|
||||||
case TOKEN:
|
|
||||||
paramType = RestSearchParameterTypeEnum.TOKEN;
|
|
||||||
break;
|
|
||||||
case URI:
|
|
||||||
paramType = RestSearchParameterTypeEnum.URI;
|
|
||||||
break;
|
|
||||||
case NULL:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (theNextSp.getStatus() != null) {
|
|
||||||
switch (theNextSp.getStatus()) {
|
|
||||||
case ACTIVE:
|
|
||||||
status = RuntimeSearchParamStatusEnum.ACTIVE;
|
|
||||||
break;
|
break;
|
||||||
case DRAFT:
|
case DATE:
|
||||||
status = RuntimeSearchParamStatusEnum.DRAFT;
|
paramType = RestSearchParameterTypeEnum.DATE;
|
||||||
break;
|
break;
|
||||||
case RETIRED:
|
case NUMBER:
|
||||||
status = RuntimeSearchParamStatusEnum.RETIRED;
|
paramType = RestSearchParameterTypeEnum.NUMBER;
|
||||||
break;
|
break;
|
||||||
case UNKNOWN:
|
case QUANTITY:
|
||||||
status = RuntimeSearchParamStatusEnum.UNKNOWN;
|
paramType = RestSearchParameterTypeEnum.QUANTITY;
|
||||||
|
break;
|
||||||
|
case REFERENCE:
|
||||||
|
paramType = RestSearchParameterTypeEnum.REFERENCE;
|
||||||
|
break;
|
||||||
|
case STRING:
|
||||||
|
paramType = RestSearchParameterTypeEnum.STRING;
|
||||||
|
break;
|
||||||
|
case TOKEN:
|
||||||
|
paramType = RestSearchParameterTypeEnum.TOKEN;
|
||||||
|
break;
|
||||||
|
case URI:
|
||||||
|
paramType = RestSearchParameterTypeEnum.URI;
|
||||||
break;
|
break;
|
||||||
case NULL:
|
case NULL:
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
if (theNextSp.getStatus() != null) {
|
||||||
|
switch (theNextSp.getStatus()) {
|
||||||
|
case ACTIVE:
|
||||||
|
status = RuntimeSearchParamStatusEnum.ACTIVE;
|
||||||
|
break;
|
||||||
|
case DRAFT:
|
||||||
|
status = RuntimeSearchParamStatusEnum.DRAFT;
|
||||||
|
break;
|
||||||
|
case RETIRED:
|
||||||
|
status = RuntimeSearchParamStatusEnum.RETIRED;
|
||||||
|
break;
|
||||||
|
case UNKNOWN:
|
||||||
|
status = RuntimeSearchParamStatusEnum.UNKNOWN;
|
||||||
|
break;
|
||||||
|
case NULL:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Set<String> providesMembershipInCompartments = Collections.emptySet();
|
Set<String> providesMembershipInCompartments = Collections.emptySet();
|
||||||
Set<String> targets = toStrings(theNextSp.getTarget());
|
Set<String> targets = DatatypeUtil.toStringSet(theNextSp.getTarget());
|
||||||
|
|
||||||
if (isBlank(name) || isBlank(path) || paramType == null) {
|
if (isBlank(name) || isBlank(path) || paramType == null) {
|
||||||
if (paramType != RestSearchParameterTypeEnum.COMPOSITE) {
|
if (paramType != RestSearchParameterTypeEnum.COMPOSITE) {
|
||||||
|
@ -250,18 +131,7 @@ public class SearchParamRegistryDstu3 extends BaseSearchParamRegistry {
|
||||||
components.add(new JpaRuntimeSearchParam.Component(next.getExpression(), next.getDefinition()));
|
components.add(new JpaRuntimeSearchParam.Component(next.getExpression(), next.getDefinition()));
|
||||||
}
|
}
|
||||||
|
|
||||||
JpaRuntimeSearchParam retVal = new JpaRuntimeSearchParam(id, uri, name, description, path, paramType, providesMembershipInCompartments, targets, status, unique, components, theNextSp.getBase());
|
return new JpaRuntimeSearchParam(id, uri, name, description, path, paramType, providesMembershipInCompartments, targets, status, unique, components, theNextSp.getBase());
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<String> toStrings(List<CodeType> theTarget) {
|
|
||||||
HashSet<String> retVal = new HashSet<String>();
|
|
||||||
for (CodeType next : theTarget) {
|
|
||||||
if (isNotBlank(next.getValue())) {
|
|
||||||
retVal.add(next.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return retVal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,14 +40,13 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
|
||||||
public class FhirResourceDaoSearchParameterR4 extends FhirResourceDaoR4<SearchParameter> implements IFhirResourceDaoSearchParameter<SearchParameter> {
|
public class FhirResourceDaoSearchParameterR4 extends FhirResourceDaoR4<SearchParameter> implements IFhirResourceDaoSearchParameter<SearchParameter> {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoSearchParameterR4.class);
|
|
||||||
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IFhirSystemDao<Bundle, Meta> mySystemDao;
|
private IFhirSystemDao<Bundle, Meta> mySystemDao;
|
||||||
|
|
||||||
protected void markAffectedResources(SearchParameter theResource) {
|
protected void markAffectedResources(SearchParameter theResource) {
|
||||||
markResourcesMatchingExpressionAsNeedingReindexing(theResource != null ? theResource.getExpression() : null);
|
Boolean reindex = theResource != null ? CURRENTLY_REINDEXING.get(theResource) : null;
|
||||||
|
String expression = theResource != null ? theResource.getExpression() : null;
|
||||||
|
markResourcesMatchingExpressionAsNeedingReindexing(reindex, expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -128,7 +127,6 @@ public class FhirResourceDaoSearchParameterR4 extends FhirResourceDaoR4<SearchPa
|
||||||
theExpression = theExpression.trim();
|
theExpression = theExpression.trim();
|
||||||
|
|
||||||
String[] expressionSplit = BaseSearchParamExtractor.SPLIT.split(theExpression);
|
String[] expressionSplit = BaseSearchParamExtractor.SPLIT.split(theExpression);
|
||||||
String allResourceName = null;
|
|
||||||
for (String nextPath : expressionSplit) {
|
for (String nextPath : expressionSplit) {
|
||||||
nextPath = nextPath.trim();
|
nextPath = nextPath.trim();
|
||||||
|
|
||||||
|
@ -144,14 +142,6 @@ public class FhirResourceDaoSearchParameterR4 extends FhirResourceDaoR4<SearchPa
|
||||||
throw new UnprocessableEntityException("Invalid SearchParameter.expression value \"" + nextPath + "\": " + e.getMessage());
|
throw new UnprocessableEntityException("Invalid SearchParameter.expression value \"" + nextPath + "\": " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allResourceName == null) {
|
|
||||||
allResourceName = resourceName;
|
|
||||||
} else {
|
|
||||||
if (!allResourceName.equals(resourceName)) {
|
|
||||||
throw new UnprocessableEntityException("Invalid SearchParameter.expression value \"" + nextPath + "\". All paths in a single SearchParameter must match the same resource type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // if have expression
|
} // if have expression
|
||||||
|
|
|
@ -29,6 +29,7 @@ import ca.uhn.fhir.jpa.entity.SubscriptionTable;
|
||||||
import ca.uhn.fhir.parser.DataFormatException;
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.model.Subscription;
|
import org.hl7.fhir.r4.model.Subscription;
|
||||||
|
@ -37,20 +38,16 @@ import org.hl7.fhir.r4.model.Subscription.SubscriptionStatus;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
|
||||||
public class FhirResourceDaoSubscriptionR4 extends FhirResourceDaoR4<Subscription> implements IFhirResourceDaoSubscription<Subscription> {
|
public class FhirResourceDaoSubscriptionR4 extends FhirResourceDaoR4<Subscription> implements IFhirResourceDaoSubscription<Subscription> {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoSubscriptionR4.class);
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISubscriptionTableDao mySubscriptionTableDao;
|
private ISubscriptionTableDao mySubscriptionTableDao;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private PlatformTransactionManager myTxManager;
|
|
||||||
|
|
||||||
private void createSubscriptionTable(ResourceTable theEntity, Subscription theSubscription) {
|
private void createSubscriptionTable(ResourceTable theEntity, Subscription theSubscription) {
|
||||||
SubscriptionTable subscriptionEntity = new SubscriptionTable();
|
SubscriptionTable subscriptionEntity = new SubscriptionTable();
|
||||||
subscriptionEntity.setCreated(new Date());
|
subscriptionEntity.setCreated(new Date());
|
||||||
|
@ -108,7 +105,18 @@ public class FhirResourceDaoSubscriptionR4 extends FhirResourceDaoR4<Subscriptio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public RuntimeResourceDefinition validateCriteriaAndReturnResourceDefinition(Subscription theResource) {
|
public RuntimeResourceDefinition validateCriteriaAndReturnResourceDefinition(Subscription theResource) {
|
||||||
|
switch (ObjectUtils.defaultIfNull(theResource.getStatus(), Subscription.SubscriptionStatus.OFF)) {
|
||||||
|
case REQUESTED:
|
||||||
|
case ACTIVE:
|
||||||
|
break;
|
||||||
|
case ERROR:
|
||||||
|
case OFF:
|
||||||
|
case NULL:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
String query = theResource.getCriteria();
|
String query = theResource.getCriteria();
|
||||||
if (isBlank(query)) {
|
if (isBlank(query)) {
|
||||||
throw new UnprocessableEntityException("Subscription.criteria must be populated");
|
throw new UnprocessableEntityException("Subscription.criteria must be populated");
|
||||||
|
@ -145,6 +153,9 @@ public class FhirResourceDaoSubscriptionR4 extends FhirResourceDaoR4<Subscriptio
|
||||||
super.validateResourceForStorage(theResource, theEntityToSave);
|
super.validateResourceForStorage(theResource, theEntityToSave);
|
||||||
|
|
||||||
RuntimeResourceDefinition resDef = validateCriteriaAndReturnResourceDefinition(theResource);
|
RuntimeResourceDefinition resDef = validateCriteriaAndReturnResourceDefinition(theResource);
|
||||||
|
if (resDef == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
IFhirResourceDao<? extends IBaseResource> dao = getDao(resDef.getImplementingClass());
|
IFhirResourceDao<? extends IBaseResource> dao = getDao(resDef.getImplementingClass());
|
||||||
if (dao == null) {
|
if (dao == null) {
|
||||||
|
|
|
@ -29,6 +29,7 @@ import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.entity.TagDefinition;
|
import ca.uhn.fhir.jpa.entity.TagDefinition;
|
||||||
import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails;
|
import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.util.DeleteConflict;
|
import ca.uhn.fhir.jpa.util.DeleteConflict;
|
||||||
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||||
import ca.uhn.fhir.parser.DataFormatException;
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
import ca.uhn.fhir.parser.IParser;
|
import ca.uhn.fhir.parser.IParser;
|
||||||
|
@ -144,7 +145,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
}
|
}
|
||||||
|
|
||||||
long delay = System.currentTimeMillis() - start;
|
long delay = System.currentTimeMillis() - start;
|
||||||
ourLog.info("Batch completed in {}ms", new Object[]{delay});
|
ourLog.info("Batch completed in {}ms", new Object[] {delay});
|
||||||
|
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
@ -169,9 +170,9 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
final Date updateTime = new Date();
|
final Date updateTime = new Date();
|
||||||
|
|
||||||
final Set<IdType> allIds = new LinkedHashSet<IdType>();
|
final Set<IdType> allIds = new LinkedHashSet<>();
|
||||||
final Map<IdType, IdType> idSubstitutions = new HashMap<IdType, IdType>();
|
final Map<IdType, IdType> idSubstitutions = new HashMap<>();
|
||||||
final Map<IdType, DaoMethodOutcome> idToPersistedOutcome = new HashMap<IdType, DaoMethodOutcome>();
|
final Map<IdType, DaoMethodOutcome> idToPersistedOutcome = new HashMap<>();
|
||||||
|
|
||||||
// Do all entries have a verb?
|
// Do all entries have a verb?
|
||||||
for (int i = 0; i < theRequest.getEntry().size(); i++) {
|
for (int i = 0; i < theRequest.getEntry().size(); i++) {
|
||||||
|
@ -193,8 +194,8 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
* we want the GET processing to use the final indexing state
|
* we want the GET processing to use the final indexing state
|
||||||
*/
|
*/
|
||||||
final Bundle response = new Bundle();
|
final Bundle response = new Bundle();
|
||||||
List<BundleEntryComponent> getEntries = new ArrayList<BundleEntryComponent>();
|
List<BundleEntryComponent> getEntries = new ArrayList<>();
|
||||||
final IdentityHashMap<BundleEntryComponent, Integer> originalRequestOrder = new IdentityHashMap<Bundle.BundleEntryComponent, Integer>();
|
final IdentityHashMap<BundleEntryComponent, Integer> originalRequestOrder = new IdentityHashMap<>();
|
||||||
for (int i = 0; i < theRequest.getEntry().size(); i++) {
|
for (int i = 0; i < theRequest.getEntry().size(); i++) {
|
||||||
originalRequestOrder.put(theRequest.getEntry().get(i), i);
|
originalRequestOrder.put(theRequest.getEntry().get(i), i);
|
||||||
response.addEntry();
|
response.addEntry();
|
||||||
|
@ -265,8 +266,8 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
paramValues.put(next.getName(), next.getValue());
|
paramValues.put(next.getName(), next.getValue());
|
||||||
}
|
}
|
||||||
for (java.util.Map.Entry<String, Collection<String>> nextParamEntry : paramValues.asMap().entrySet()) {
|
for (java.util.Map.Entry<String, Collection<String>> nextParamEntry : paramValues.asMap().entrySet()) {
|
||||||
String[] nextValue = nextParamEntry.getValue().toArray(new String[nextParamEntry.getValue().size()]);
|
String[] nextValue = nextParamEntry.getValue().toArray(new String[ nextParamEntry.getValue().size() ]);
|
||||||
requestDetails.getParameters().put(nextParamEntry.getKey(), nextValue);
|
requestDetails.addParameter(nextParamEntry.getKey(), nextValue);
|
||||||
}
|
}
|
||||||
url = url.substring(0, qIndex);
|
url = url.substring(0, qIndex);
|
||||||
}
|
}
|
||||||
|
@ -290,7 +291,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
requestDetails.addHeader(Constants.HEADER_IF_NONE_MATCH, nextReqEntry.getRequest().getIfNoneMatch());
|
requestDetails.addHeader(Constants.HEADER_IF_NONE_MATCH, nextReqEntry.getRequest().getIfNoneMatch());
|
||||||
}
|
}
|
||||||
|
|
||||||
Validate.isTrue(method instanceof BaseResourceReturningMethodBinding, "Unable to handle GET {}", url);
|
Validate.isTrue(method instanceof BaseResourceReturningMethodBinding, "Unable to handle GET {0}", url);
|
||||||
try {
|
try {
|
||||||
IBaseResource resource = ((BaseResourceReturningMethodBinding) method).doInvokeServer(theRequestDetails.getServer(), requestDetails);
|
IBaseResource resource = ((BaseResourceReturningMethodBinding) method).doInvokeServer(theRequestDetails.getServer(), requestDetails);
|
||||||
if (paramValues.containsKey(Constants.PARAM_SUMMARY) || paramValues.containsKey(Constants.PARAM_CONTENT)) {
|
if (paramValues.containsKey(Constants.PARAM_SUMMARY) || paramValues.containsKey(Constants.PARAM_CONTENT)) {
|
||||||
|
@ -309,20 +310,20 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
}
|
}
|
||||||
|
|
||||||
long delay = System.currentTimeMillis() - start;
|
long delay = System.currentTimeMillis() - start;
|
||||||
ourLog.info(theActionName + " completed in {}ms", new Object[]{delay});
|
ourLog.info(theActionName + " completed in {}ms", new Object[] {delay});
|
||||||
|
|
||||||
response.setType(BundleType.TRANSACTIONRESPONSE);
|
response.setType(BundleType.TRANSACTIONRESPONSE);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private Map<BundleEntryComponent, ResourceTable> doTransactionWriteOperations(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName, Date updateTime, Set<IdType> allIds,
|
private Map<BundleEntryComponent, ResourceTable> doTransactionWriteOperations(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName, Date theUpdateTime, Set<IdType> theAllIds,
|
||||||
Map<IdType, IdType> idSubstitutions, Map<IdType, DaoMethodOutcome> idToPersistedOutcome, Bundle response, IdentityHashMap<BundleEntryComponent, Integer> originalRequestOrder, List<BundleEntryComponent> theEntries) {
|
Map<IdType, IdType> theIdSubstitutions, Map<IdType, DaoMethodOutcome> theIdToPersistedOutcome, Bundle theResponse, IdentityHashMap<BundleEntryComponent, Integer> theOriginalRequestOrder, List<BundleEntryComponent> theEntries) {
|
||||||
Set<String> deletedResources = new HashSet<String>();
|
Set<String> deletedResources = new HashSet<>();
|
||||||
List<DeleteConflict> deleteConflicts = new ArrayList<DeleteConflict>();
|
List<DeleteConflict> deleteConflicts = new ArrayList<>();
|
||||||
Map<BundleEntryComponent, ResourceTable> entriesToProcess = new IdentityHashMap<BundleEntryComponent, ResourceTable>();
|
Map<BundleEntryComponent, ResourceTable> entriesToProcess = new IdentityHashMap<>();
|
||||||
Set<ResourceTable> nonUpdatedEntities = new HashSet<ResourceTable>();
|
Set<ResourceTable> nonUpdatedEntities = new HashSet<>();
|
||||||
Map<String, Class<? extends IBaseResource>> conditionalRequestUrls = new HashMap<String, Class<? extends IBaseResource>>();
|
Map<String, Class<? extends IBaseResource>> conditionalRequestUrls = new HashMap<>();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Loop through the request and process any entries of type
|
* Loop through the request and process any entries of type
|
||||||
|
@ -341,7 +342,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
|
|
||||||
nextResourceId = res.getIdElement();
|
nextResourceId = res.getIdElement();
|
||||||
|
|
||||||
if (nextResourceId.hasIdPart() == false) {
|
if (!nextResourceId.hasIdPart()) {
|
||||||
if (isNotBlank(nextReqEntry.getFullUrl())) {
|
if (isNotBlank(nextReqEntry.getFullUrl())) {
|
||||||
nextResourceId = new IdType(nextReqEntry.getFullUrl());
|
nextResourceId = new IdType(nextReqEntry.getFullUrl());
|
||||||
}
|
}
|
||||||
|
@ -360,12 +361,12 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
* Ensure that the bundle doesn't have any duplicates, since this causes all kinds of weirdness
|
* Ensure that the bundle doesn't have any duplicates, since this causes all kinds of weirdness
|
||||||
*/
|
*/
|
||||||
if (isPlaceholder(nextResourceId)) {
|
if (isPlaceholder(nextResourceId)) {
|
||||||
if (!allIds.add(nextResourceId)) {
|
if (!theAllIds.add(nextResourceId)) {
|
||||||
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionContainsMultipleWithDuplicateId", nextResourceId));
|
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionContainsMultipleWithDuplicateId", nextResourceId));
|
||||||
}
|
}
|
||||||
} else if (nextResourceId.hasResourceType() && nextResourceId.hasIdPart()) {
|
} else if (nextResourceId.hasResourceType() && nextResourceId.hasIdPart()) {
|
||||||
IdType nextId = nextResourceId.toUnqualifiedVersionless();
|
IdType nextId = nextResourceId.toUnqualifiedVersionless();
|
||||||
if (!allIds.add(nextId)) {
|
if (!theAllIds.add(nextId)) {
|
||||||
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionContainsMultipleWithDuplicateId", nextId));
|
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionContainsMultipleWithDuplicateId", nextId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -375,7 +376,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
HTTPVerb verb = nextReqEntry.getRequest().getMethodElement().getValue();
|
HTTPVerb verb = nextReqEntry.getRequest().getMethodElement().getValue();
|
||||||
|
|
||||||
String resourceType = res != null ? getContext().getResourceDefinition(res).getName() : null;
|
String resourceType = res != null ? getContext().getResourceDefinition(res).getName() : null;
|
||||||
BundleEntryComponent nextRespEntry = response.getEntry().get(originalRequestOrder.get(nextReqEntry));
|
BundleEntryComponent nextRespEntry = theResponse.getEntry().get(theOriginalRequestOrder.get(nextReqEntry));
|
||||||
|
|
||||||
switch (verb) {
|
switch (verb) {
|
||||||
case POST: {
|
case POST: {
|
||||||
|
@ -385,10 +386,10 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
res.setId((String) null);
|
res.setId((String) null);
|
||||||
DaoMethodOutcome outcome;
|
DaoMethodOutcome outcome;
|
||||||
String matchUrl = nextReqEntry.getRequest().getIfNoneExist();
|
String matchUrl = nextReqEntry.getRequest().getIfNoneExist();
|
||||||
matchUrl = performIdSubstitutionsInMatchUrl(idSubstitutions, matchUrl);
|
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
||||||
outcome = resourceDao.create(res, matchUrl, false, theRequestDetails);
|
outcome = resourceDao.create(res, matchUrl, false, theRequestDetails);
|
||||||
if (nextResourceId != null) {
|
if (nextResourceId != null) {
|
||||||
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, theIdToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
||||||
}
|
}
|
||||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||||
if (outcome.getCreated() == false) {
|
if (outcome.getCreated() == false) {
|
||||||
|
@ -418,7 +419,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
String matchUrl = parts.getResourceType() + '?' + parts.getParams();
|
String matchUrl = parts.getResourceType() + '?' + parts.getParams();
|
||||||
matchUrl = performIdSubstitutionsInMatchUrl(idSubstitutions, matchUrl);
|
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
||||||
DeleteMethodOutcome deleteOutcome = dao.deleteByUrl(matchUrl, deleteConflicts, theRequestDetails);
|
DeleteMethodOutcome deleteOutcome = dao.deleteByUrl(matchUrl, deleteConflicts, theRequestDetails);
|
||||||
List<ResourceTable> allDeleted = deleteOutcome.getDeletedEntities();
|
List<ResourceTable> allDeleted = deleteOutcome.getDeletedEntities();
|
||||||
for (ResourceTable deleted : allDeleted) {
|
for (ResourceTable deleted : allDeleted) {
|
||||||
|
@ -459,14 +460,14 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
} else {
|
} else {
|
||||||
matchUrl = parts.getResourceType();
|
matchUrl = parts.getResourceType();
|
||||||
}
|
}
|
||||||
matchUrl = performIdSubstitutionsInMatchUrl(idSubstitutions, matchUrl);
|
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
||||||
outcome = resourceDao.update(res, matchUrl, false, theRequestDetails);
|
outcome = resourceDao.update(res, matchUrl, false, theRequestDetails);
|
||||||
if (Boolean.TRUE.equals(outcome.getCreated())) {
|
if (Boolean.TRUE.equals(outcome.getCreated())) {
|
||||||
conditionalRequestUrls.put(matchUrl, res.getClass());
|
conditionalRequestUrls.put(matchUrl, res.getClass());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, theIdToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
||||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -499,21 +500,22 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
FhirTerser terser = getContext().newTerser();
|
FhirTerser terser = getContext().newTerser();
|
||||||
for (DaoMethodOutcome nextOutcome : idToPersistedOutcome.values()) {
|
for (DaoMethodOutcome nextOutcome : theIdToPersistedOutcome.values()) {
|
||||||
IBaseResource nextResource = nextOutcome.getResource();
|
IBaseResource nextResource = nextOutcome.getResource();
|
||||||
if (nextResource == null) {
|
if (nextResource == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// References
|
||||||
List<IBaseReference> allRefs = terser.getAllPopulatedChildElementsOfType(nextResource, IBaseReference.class);
|
List<IBaseReference> allRefs = terser.getAllPopulatedChildElementsOfType(nextResource, IBaseReference.class);
|
||||||
for (IBaseReference nextRef : allRefs) {
|
for (IBaseReference nextRef : allRefs) {
|
||||||
IIdType nextId = nextRef.getReferenceElement();
|
IIdType nextId = nextRef.getReferenceElement();
|
||||||
if (!nextId.hasIdPart()) {
|
if (!nextId.hasIdPart()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (idSubstitutions.containsKey(nextId)) {
|
if (theIdSubstitutions.containsKey(nextId)) {
|
||||||
IdType newId = idSubstitutions.get(nextId);
|
IdType newId = theIdSubstitutions.get(nextId);
|
||||||
ourLog.info(" * Replacing resource ref {} with {}", nextId, newId);
|
ourLog.debug(" * Replacing resource ref {} with {}", nextId, newId);
|
||||||
nextRef.setReference(newId.getValue());
|
nextRef.setReference(newId.getValue());
|
||||||
} else if (nextId.getValue().startsWith("urn:")) {
|
} else if (nextId.getValue().startsWith("urn:")) {
|
||||||
throw new InvalidRequestException("Unable to satisfy placeholder ID: " + nextId.getValue());
|
throw new InvalidRequestException("Unable to satisfy placeholder ID: " + nextId.getValue());
|
||||||
|
@ -522,15 +524,31 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// URIs
|
||||||
|
List<UriType> allUris = terser.getAllPopulatedChildElementsOfType(nextResource, UriType.class);
|
||||||
|
for (UriType nextRef : allUris) {
|
||||||
|
if (nextRef instanceof IIdType) {
|
||||||
|
continue; // No substitution on the resource ID itself!
|
||||||
|
}
|
||||||
|
IdType nextUriString = new IdType(nextRef.getValueAsString());
|
||||||
|
if (theIdSubstitutions.containsKey(nextUriString)) {
|
||||||
|
IdType newId = theIdSubstitutions.get(nextUriString);
|
||||||
|
ourLog.debug(" * Replacing resource ref {} with {}", nextUriString, newId);
|
||||||
|
nextRef.setValue(newId.getValue());
|
||||||
|
} else {
|
||||||
|
ourLog.debug(" * Reference [{}] does not exist in bundle", nextUriString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IPrimitiveType<Date> deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get((IAnyResource) nextResource);
|
IPrimitiveType<Date> deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get((IAnyResource) nextResource);
|
||||||
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
||||||
boolean shouldUpdate = !nonUpdatedEntities.contains(nextOutcome.getEntity());
|
boolean shouldUpdate = !nonUpdatedEntities.contains(nextOutcome.getEntity());
|
||||||
if (shouldUpdate) {
|
if (shouldUpdate) {
|
||||||
updateEntity(nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, shouldUpdate, false, updateTime, false, true);
|
updateEntity(nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, shouldUpdate, false, theUpdateTime, false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
myEntityManager.flush();
|
flushJpaSession();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Double check we didn't allow any duplicates we shouldn't have
|
* Double check we didn't allow any duplicates we shouldn't have
|
||||||
|
@ -548,15 +566,15 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (IdType next : allIds) {
|
for (IdType next : theAllIds) {
|
||||||
IdType replacement = idSubstitutions.get(next);
|
IdType replacement = theIdSubstitutions.get(next);
|
||||||
if (replacement == null) {
|
if (replacement == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (replacement.equals(next)) {
|
if (replacement.equals(next)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ourLog.info("Placeholder resource ID \"{}\" was replaced with permanent ID \"{}\"", next, replacement);
|
ourLog.debug("Placeholder resource ID \"{}\" was replaced with permanent ID \"{}\"", next, replacement);
|
||||||
}
|
}
|
||||||
return entriesToProcess;
|
return entriesToProcess;
|
||||||
}
|
}
|
||||||
|
@ -601,9 +619,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
TypedQuery<TagDefinition> q = myEntityManager.createQuery(sql, TagDefinition.class);
|
TypedQuery<TagDefinition> q = myEntityManager.createQuery(sql, TagDefinition.class);
|
||||||
List<TagDefinition> tagDefinitions = q.getResultList();
|
List<TagDefinition> tagDefinitions = q.getResultList();
|
||||||
|
|
||||||
Meta retVal = toMeta(tagDefinitions);
|
return toMeta(tagDefinitions);
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String performIdSubstitutionsInMatchUrl(Map<IdType, IdType> theIdSubstitutions, String theMatchUrl) {
|
private String performIdSubstitutionsInMatchUrl(Map<IdType, IdType> theIdSubstitutions, String theMatchUrl) {
|
||||||
|
|
|
@ -20,211 +20,93 @@ package ca.uhn.fhir.jpa.dao.r4;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.search.JpaRuntimeSearchParam;
|
|
||||||
import ca.uhn.fhir.jpa.util.JpaConstants;
|
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
|
||||||
import org.hl7.fhir.r4.model.CodeType;
|
|
||||||
import org.hl7.fhir.r4.model.Extension;
|
|
||||||
import org.hl7.fhir.r4.model.SearchParameter;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam.RuntimeSearchParamStatusEnum;
|
import ca.uhn.fhir.context.RuntimeSearchParam.RuntimeSearchParamStatusEnum;
|
||||||
import ca.uhn.fhir.jpa.dao.*;
|
import ca.uhn.fhir.jpa.dao.BaseSearchParamRegistry;
|
||||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||||
|
import ca.uhn.fhir.jpa.search.JpaRuntimeSearchParam;
|
||||||
|
import ca.uhn.fhir.jpa.util.JpaConstants;
|
||||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.util.DatatypeUtil;
|
||||||
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
import org.hl7.fhir.r4.model.Extension;
|
||||||
|
import org.hl7.fhir.r4.model.Reference;
|
||||||
|
import org.hl7.fhir.r4.model.SearchParameter;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
public class SearchParamRegistryR4 extends BaseSearchParamRegistry {
|
import java.util.ArrayList;
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParamRegistryR4.class);
|
import java.util.Collections;
|
||||||
public static final int MAX_MANAGED_PARAM_COUNT = 10000;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
private volatile Map<String, Map<String, RuntimeSearchParam>> myActiveSearchParams;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
|
||||||
@Autowired
|
public class SearchParamRegistryR4 extends BaseSearchParamRegistry<SearchParameter> {
|
||||||
private DaoConfig myDaoConfig;
|
|
||||||
|
|
||||||
private volatile long myLastRefresh;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IFhirResourceDao<SearchParameter> mySpDao;
|
private IFhirResourceDao<SearchParameter> mySpDao;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void forceRefresh() {
|
public IFhirResourceDao<SearchParameter> getSearchParameterDao() {
|
||||||
synchronized (this) {
|
return mySpDao;
|
||||||
myLastRefresh = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Map<String, RuntimeSearchParam>> getActiveSearchParams() {
|
protected RuntimeSearchParam toRuntimeSp(SearchParameter theNextSp) {
|
||||||
refreshCacheIfNecessary();
|
|
||||||
return myActiveSearchParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, RuntimeSearchParam> getActiveSearchParams(String theResourceName) {
|
|
||||||
refreshCacheIfNecessary();
|
|
||||||
return myActiveSearchParams.get(theResourceName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, RuntimeSearchParam> getSearchParamMap(Map<String, Map<String, RuntimeSearchParam>> searchParams, String theResourceName) {
|
|
||||||
Map<String, RuntimeSearchParam> retVal = searchParams.get(theResourceName);
|
|
||||||
if (retVal == null) {
|
|
||||||
retVal = new HashMap<>();
|
|
||||||
searchParams.put(theResourceName, retVal);
|
|
||||||
}
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void refreshCacheIfNecessary() {
|
|
||||||
long refreshInterval = 60 * DateUtils.MILLIS_PER_MINUTE;
|
|
||||||
if (System.currentTimeMillis() - refreshInterval > myLastRefresh) {
|
|
||||||
synchronized (this) {
|
|
||||||
if (System.currentTimeMillis() - refreshInterval > myLastRefresh) {
|
|
||||||
StopWatch sw = new StopWatch();
|
|
||||||
|
|
||||||
Map<String, Map<String, RuntimeSearchParam>> searchParams = new HashMap<>();
|
|
||||||
for (Entry<String, Map<String, RuntimeSearchParam>> nextBuiltInEntry : getBuiltInSearchParams().entrySet()) {
|
|
||||||
for (RuntimeSearchParam nextParam : nextBuiltInEntry.getValue().values()) {
|
|
||||||
String nextResourceName = nextBuiltInEntry.getKey();
|
|
||||||
getSearchParamMap(searchParams, nextResourceName).put(nextParam.getName(), nextParam);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchParameterMap params = new SearchParameterMap();
|
|
||||||
params.setLoadSynchronousUpTo(MAX_MANAGED_PARAM_COUNT);
|
|
||||||
|
|
||||||
IBundleProvider allSearchParamsBp = mySpDao.search(params);
|
|
||||||
int size = allSearchParamsBp.size();
|
|
||||||
|
|
||||||
// Just in case..
|
|
||||||
if (size >= MAX_MANAGED_PARAM_COUNT) {
|
|
||||||
ourLog.warn("Unable to support >" + MAX_MANAGED_PARAM_COUNT + " search params!");
|
|
||||||
size = MAX_MANAGED_PARAM_COUNT;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<IBaseResource> allSearchParams = allSearchParamsBp.getResources(0, size);
|
|
||||||
for (IBaseResource nextResource : allSearchParams) {
|
|
||||||
SearchParameter nextSp = (SearchParameter) nextResource;
|
|
||||||
RuntimeSearchParam runtimeSp = toRuntimeSp(nextSp);
|
|
||||||
if (runtimeSp == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (CodeType nextBaseName : nextSp.getBase()) {
|
|
||||||
String resourceType = nextBaseName.getValue();
|
|
||||||
if (isBlank(resourceType)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, RuntimeSearchParam> searchParamMap = getSearchParamMap(searchParams, resourceType);
|
|
||||||
String name = runtimeSp.getName();
|
|
||||||
if (myDaoConfig.isDefaultSearchParamsCanBeOverridden() || !searchParamMap.containsKey(name)) {
|
|
||||||
searchParamMap.put(name, runtimeSp);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, Map<String, RuntimeSearchParam>> activeSearchParams = new HashMap<>();
|
|
||||||
for (Entry<String, Map<String, RuntimeSearchParam>> nextEntry : searchParams.entrySet()) {
|
|
||||||
for (RuntimeSearchParam nextSp : nextEntry.getValue().values()) {
|
|
||||||
String nextName = nextSp.getName();
|
|
||||||
if (nextSp.getStatus() != RuntimeSearchParamStatusEnum.ACTIVE) {
|
|
||||||
nextSp = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!activeSearchParams.containsKey(nextEntry.getKey())) {
|
|
||||||
activeSearchParams.put(nextEntry.getKey(), new HashMap<String, RuntimeSearchParam>());
|
|
||||||
}
|
|
||||||
if (activeSearchParams.containsKey(nextEntry.getKey())) {
|
|
||||||
ourLog.debug("Replacing existing/built in search param {}:{} with new one", nextEntry.getKey(), nextName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextSp != null) {
|
|
||||||
activeSearchParams.get(nextEntry.getKey()).put(nextName, nextSp);
|
|
||||||
} else {
|
|
||||||
activeSearchParams.get(nextEntry.getKey()).remove(nextName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
myActiveSearchParams = activeSearchParams;
|
|
||||||
|
|
||||||
super.populateActiveSearchParams(activeSearchParams);
|
|
||||||
|
|
||||||
myLastRefresh = System.currentTimeMillis();
|
|
||||||
ourLog.info("Refreshed search parameter cache in {}ms", sw.getMillis());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private RuntimeSearchParam toRuntimeSp(SearchParameter theNextSp) {
|
|
||||||
String name = theNextSp.getCode();
|
String name = theNextSp.getCode();
|
||||||
String description = theNextSp.getDescription();
|
String description = theNextSp.getDescription();
|
||||||
String path = theNextSp.getExpression();
|
String path = theNextSp.getExpression();
|
||||||
RestSearchParameterTypeEnum paramType = null;
|
RestSearchParameterTypeEnum paramType = null;
|
||||||
RuntimeSearchParamStatusEnum status = null;
|
RuntimeSearchParamStatusEnum status = null;
|
||||||
switch (theNextSp.getType()) {
|
switch (theNextSp.getType()) {
|
||||||
case COMPOSITE:
|
case COMPOSITE:
|
||||||
paramType = RestSearchParameterTypeEnum.COMPOSITE;
|
paramType = RestSearchParameterTypeEnum.COMPOSITE;
|
||||||
break;
|
|
||||||
case DATE:
|
|
||||||
paramType = RestSearchParameterTypeEnum.DATE;
|
|
||||||
break;
|
|
||||||
case NUMBER:
|
|
||||||
paramType = RestSearchParameterTypeEnum.NUMBER;
|
|
||||||
break;
|
|
||||||
case QUANTITY:
|
|
||||||
paramType = RestSearchParameterTypeEnum.QUANTITY;
|
|
||||||
break;
|
|
||||||
case REFERENCE:
|
|
||||||
paramType = RestSearchParameterTypeEnum.REFERENCE;
|
|
||||||
break;
|
|
||||||
case STRING:
|
|
||||||
paramType = RestSearchParameterTypeEnum.STRING;
|
|
||||||
break;
|
|
||||||
case TOKEN:
|
|
||||||
paramType = RestSearchParameterTypeEnum.TOKEN;
|
|
||||||
break;
|
|
||||||
case URI:
|
|
||||||
paramType = RestSearchParameterTypeEnum.URI;
|
|
||||||
break;
|
|
||||||
case NULL:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (theNextSp.getStatus() != null) {
|
|
||||||
switch (theNextSp.getStatus()) {
|
|
||||||
case ACTIVE:
|
|
||||||
status = RuntimeSearchParamStatusEnum.ACTIVE;
|
|
||||||
break;
|
break;
|
||||||
case DRAFT:
|
case DATE:
|
||||||
status = RuntimeSearchParamStatusEnum.DRAFT;
|
paramType = RestSearchParameterTypeEnum.DATE;
|
||||||
break;
|
break;
|
||||||
case RETIRED:
|
case NUMBER:
|
||||||
status = RuntimeSearchParamStatusEnum.RETIRED;
|
paramType = RestSearchParameterTypeEnum.NUMBER;
|
||||||
break;
|
break;
|
||||||
case UNKNOWN:
|
case QUANTITY:
|
||||||
status = RuntimeSearchParamStatusEnum.UNKNOWN;
|
paramType = RestSearchParameterTypeEnum.QUANTITY;
|
||||||
|
break;
|
||||||
|
case REFERENCE:
|
||||||
|
paramType = RestSearchParameterTypeEnum.REFERENCE;
|
||||||
|
break;
|
||||||
|
case STRING:
|
||||||
|
paramType = RestSearchParameterTypeEnum.STRING;
|
||||||
|
break;
|
||||||
|
case TOKEN:
|
||||||
|
paramType = RestSearchParameterTypeEnum.TOKEN;
|
||||||
|
break;
|
||||||
|
case URI:
|
||||||
|
paramType = RestSearchParameterTypeEnum.URI;
|
||||||
break;
|
break;
|
||||||
case NULL:
|
case NULL:
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
if (theNextSp.getStatus() != null) {
|
||||||
|
switch (theNextSp.getStatus()) {
|
||||||
|
case ACTIVE:
|
||||||
|
status = RuntimeSearchParamStatusEnum.ACTIVE;
|
||||||
|
break;
|
||||||
|
case DRAFT:
|
||||||
|
status = RuntimeSearchParamStatusEnum.DRAFT;
|
||||||
|
break;
|
||||||
|
case RETIRED:
|
||||||
|
status = RuntimeSearchParamStatusEnum.RETIRED;
|
||||||
|
break;
|
||||||
|
case UNKNOWN:
|
||||||
|
status = RuntimeSearchParamStatusEnum.UNKNOWN;
|
||||||
|
break;
|
||||||
|
case NULL:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Set<String> providesMembershipInCompartments = Collections.emptySet();
|
Set<String> providesMembershipInCompartments = Collections.emptySet();
|
||||||
Set<String> targets = toStrings(theNextSp.getTarget());
|
Set<String> targets = DatatypeUtil.toStringSet(theNextSp.getTarget());
|
||||||
|
|
||||||
if (isBlank(name) || isBlank(path) || paramType == null) {
|
if (isBlank(name) || isBlank(path) || paramType == null) {
|
||||||
if (paramType != RestSearchParameterTypeEnum.COMPOSITE) {
|
if (paramType != RestSearchParameterTypeEnum.COMPOSITE) {
|
||||||
|
@ -248,21 +130,11 @@ public class SearchParamRegistryR4 extends BaseSearchParamRegistry {
|
||||||
|
|
||||||
List<JpaRuntimeSearchParam.Component> components = new ArrayList<>();
|
List<JpaRuntimeSearchParam.Component> components = new ArrayList<>();
|
||||||
for (org.hl7.fhir.r4.model.SearchParameter.SearchParameterComponentComponent next : theNextSp.getComponent()) {
|
for (org.hl7.fhir.r4.model.SearchParameter.SearchParameterComponentComponent next : theNextSp.getComponent()) {
|
||||||
components.add(new JpaRuntimeSearchParam.Component(next.getExpression(), next.getDefinition()));
|
components.add(new JpaRuntimeSearchParam.Component(next.getExpression(), new Reference(next.getDefinition())));
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimeSearchParam retVal = new JpaRuntimeSearchParam(id, uri, name, description, path, paramType, providesMembershipInCompartments, targets, status, unique, components, theNextSp.getBase());
|
return new JpaRuntimeSearchParam(id, uri, name, description, path, paramType, providesMembershipInCompartments, targets, status, unique, components, theNextSp.getBase());
|
||||||
return retVal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<String> toStrings(List<CodeType> theTarget) {
|
|
||||||
HashSet<String> retVal = new HashSet<>();
|
|
||||||
for (CodeType next : theTarget) {
|
|
||||||
if (isNotBlank(next.getValue())) {
|
|
||||||
retVal.add(next.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ public abstract class BaseHasResource {
|
||||||
@Temporal(TemporalType.TIMESTAMP)
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
private Date myDeleted;
|
private Date myDeleted;
|
||||||
|
|
||||||
|
// TODO: move to resource history table
|
||||||
@Column(name = "RES_VERSION", nullable = true, length = 7)
|
@Column(name = "RES_VERSION", nullable = true, length = 7)
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
@OptimisticLock(excluded = true)
|
@OptimisticLock(excluded = true)
|
||||||
|
|
|
@ -20,24 +20,15 @@ package ca.uhn.fhir.jpa.entity;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import javax.persistence.Column;
|
|
||||||
import javax.persistence.Embeddable;
|
|
||||||
import javax.persistence.Entity;
|
|
||||||
import javax.persistence.GeneratedValue;
|
|
||||||
import javax.persistence.GenerationType;
|
|
||||||
import javax.persistence.Id;
|
|
||||||
import javax.persistence.Index;
|
|
||||||
import javax.persistence.SequenceGenerator;
|
|
||||||
import javax.persistence.Table;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||||
import com.sun.prism.image.Coords;
|
|
||||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
import org.hibernate.search.annotations.Field;
|
import org.hibernate.search.annotations.Field;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
@Embeddable
|
@Embeddable
|
||||||
@Entity
|
@Entity
|
||||||
|
|
|
@ -29,13 +29,13 @@ import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
|
|
||||||
public class ServletSubRequestDetails extends ServletRequestDetails {
|
public class ServletSubRequestDetails extends ServletRequestDetails {
|
||||||
|
|
||||||
private Map<String, ArrayList<String>> myHeaders = new HashMap<String, ArrayList<String>>();
|
private Map<String, ArrayList<String>> myHeaders = new HashMap<>();
|
||||||
|
|
||||||
public void addHeader(String theName, String theValue) {
|
public void addHeader(String theName, String theValue) {
|
||||||
String lowerCase = theName.toLowerCase();
|
String lowerCase = theName.toLowerCase();
|
||||||
ArrayList<String> list = myHeaders.get(lowerCase);
|
ArrayList<String> list = myHeaders.get(lowerCase);
|
||||||
if (list == null) {
|
if (list == null) {
|
||||||
list = new ArrayList<String>();
|
list = new ArrayList<>();
|
||||||
myHeaders.put(lowerCase, list);
|
myHeaders.put(lowerCase, list);
|
||||||
}
|
}
|
||||||
list.add(theValue);
|
list.add(theValue);
|
||||||
|
|
|
@ -29,7 +29,7 @@ import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.ISearchIncludeDao;
|
import ca.uhn.fhir.jpa.dao.data.ISearchIncludeDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
|
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
|
||||||
import ca.uhn.fhir.jpa.entity.*;
|
import ca.uhn.fhir.jpa.entity.*;
|
||||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import ca.uhn.fhir.model.api.Include;
|
import ca.uhn.fhir.model.api.Include;
|
||||||
import ca.uhn.fhir.rest.api.CacheControlDirective;
|
import ca.uhn.fhir.rest.api.CacheControlDirective;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
|
|
|
@ -37,6 +37,7 @@ import org.springframework.transaction.TransactionStatus;
|
||||||
import org.springframework.transaction.annotation.Propagation;
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.transaction.support.TransactionCallback;
|
import org.springframework.transaction.support.TransactionCallback;
|
||||||
|
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -95,17 +96,24 @@ public class StaleSearchDeletingSvcImpl implements IStaleSearchDeletingSvc {
|
||||||
ourLog.debug("Searching for searches which are before {}", cutoff);
|
ourLog.debug("Searching for searches which are before {}", cutoff);
|
||||||
|
|
||||||
TransactionTemplate tt = new TransactionTemplate(myTransactionManager);
|
TransactionTemplate tt = new TransactionTemplate(myTransactionManager);
|
||||||
int count = tt.execute(new TransactionCallback<Integer>() {
|
final Slice<Long> toDelete = tt.execute(new TransactionCallback<Slice<Long>>() {
|
||||||
@Override
|
@Override
|
||||||
public Integer doInTransaction(TransactionStatus theStatus) {
|
public Slice<Long> doInTransaction(TransactionStatus theStatus) {
|
||||||
Slice<Long> toDelete = mySearchDao.findWhereLastReturnedBefore(cutoff, new PageRequest(0, 1000));
|
return mySearchDao.findWhereLastReturnedBefore(cutoff, new PageRequest(0, 1000));
|
||||||
for (final Long next : toDelete) {
|
|
||||||
deleteSearch(next);
|
|
||||||
}
|
|
||||||
return toDelete.getContent().size();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
for (final Long nextSearchToDelete : toDelete) {
|
||||||
|
ourLog.debug("Deleting search with PID {}", nextSearchToDelete);
|
||||||
|
tt.execute(new TransactionCallbackWithoutResult() {
|
||||||
|
@Override
|
||||||
|
protected void doInTransactionWithoutResult(TransactionStatus status) {
|
||||||
|
deleteSearch(nextSearchToDelete);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = toDelete.getContent().size();
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
long total = tt.execute(new TransactionCallback<Long>() {
|
long total = tt.execute(new TransactionCallback<Long>() {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -21,6 +21,9 @@ package ca.uhn.fhir.jpa.subscription;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.model.Subscription;
|
import org.hl7.fhir.r4.model.Subscription;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -29,6 +32,7 @@ import org.springframework.messaging.MessagingException;
|
||||||
|
|
||||||
public abstract class BaseSubscriptionDeliverySubscriber extends BaseSubscriptionSubscriber {
|
public abstract class BaseSubscriptionDeliverySubscriber extends BaseSubscriptionSubscriber {
|
||||||
private static final Logger ourLog = LoggerFactory.getLogger(BaseSubscriptionDeliverySubscriber.class);
|
private static final Logger ourLog = LoggerFactory.getLogger(BaseSubscriptionDeliverySubscriber.class);
|
||||||
|
private boolean myReloadResourceBeforeDelivery = true;
|
||||||
|
|
||||||
public BaseSubscriptionDeliverySubscriber(IFhirResourceDao<?> theSubscriptionDao, Subscription.SubscriptionChannelType theChannelType, BaseSubscriptionInterceptor theSubscriptionInterceptor) {
|
public BaseSubscriptionDeliverySubscriber(IFhirResourceDao<?> theSubscriptionDao, Subscription.SubscriptionChannelType theChannelType, BaseSubscriptionInterceptor theSubscriptionInterceptor) {
|
||||||
super(theSubscriptionDao, theChannelType, theSubscriptionInterceptor);
|
super(theSubscriptionDao, theChannelType, theSubscriptionInterceptor);
|
||||||
|
@ -40,24 +44,54 @@ public abstract class BaseSubscriptionDeliverySubscriber extends BaseSubscriptio
|
||||||
ourLog.warn("Unexpected payload type: {}", theMessage.getPayload());
|
ourLog.warn("Unexpected payload type: {}", theMessage.getPayload());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String subscriptionId = "(unknown?)";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ResourceDeliveryMessage msg = (ResourceDeliveryMessage) theMessage.getPayload();
|
ResourceDeliveryMessage msg = (ResourceDeliveryMessage) theMessage.getPayload();
|
||||||
|
subscriptionId = msg.getPayload(getContext()).getIdElement().getValue();
|
||||||
|
|
||||||
if (!subscriptionTypeApplies(getContext(), msg.getSubscription().getBackingSubscription(getContext()))) {
|
if (!subscriptionTypeApplies(getContext(), msg.getSubscription().getBackingSubscription(getContext()))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CanonicalSubscription updatedSubscription = (CanonicalSubscription)getSubscriptionInterceptor().getIdToSubscription().get(msg.getSubscription().getIdElement(getContext()).getIdPart());
|
CanonicalSubscription updatedSubscription = (CanonicalSubscription) getSubscriptionInterceptor().getIdToSubscription().get(msg.getSubscription().getIdElement(getContext()).getIdPart());
|
||||||
if (updatedSubscription != null) {
|
if (updatedSubscription != null) {
|
||||||
msg.setSubscription(updatedSubscription);
|
msg.setSubscription(updatedSubscription);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (myReloadResourceBeforeDelivery) {
|
||||||
|
// Reload the payload just in case any interceptors modified
|
||||||
|
// it before it was saved to the database. This is also
|
||||||
|
// useful for resources created in a transaction, since they
|
||||||
|
// can have placeholder IDs in them.
|
||||||
|
IIdType payloadId = msg.getPayloadId(getContext());
|
||||||
|
Class type = getContext().getResourceDefinition(payloadId.getResourceType()).getImplementingClass();
|
||||||
|
IFhirResourceDao dao = getSubscriptionDao().getDao(type);
|
||||||
|
IBaseResource loadedPayload;
|
||||||
|
try {
|
||||||
|
loadedPayload = dao.read(payloadId);
|
||||||
|
} catch (ResourceNotFoundException e) {
|
||||||
|
// This can happen if a last minute failure happens when saving a resource,
|
||||||
|
// eg a constraint causes the transaction to roll back on commit
|
||||||
|
ourLog.warn("Unable to find resource {} - Aborting delivery", payloadId.getValue());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
msg.setPayload(getContext(), loadedPayload);
|
||||||
|
}
|
||||||
|
|
||||||
handleMessage(msg);
|
handleMessage(msg);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ourLog.error("Failure handling subscription payload", e);
|
String msg = "Failure handling subscription payload for subscription: " + subscriptionId;
|
||||||
throw new MessagingException(theMessage, "Failure handling subscription payload", e);
|
ourLog.error(msg, e);
|
||||||
|
throw new MessagingException(theMessage, msg, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void handleMessage(ResourceDeliveryMessage theMessage) throws Exception;
|
public abstract void handleMessage(ResourceDeliveryMessage theMessage) throws Exception;
|
||||||
|
|
||||||
|
public void setReloadResourceBeforeDelivery(boolean theReloadResourceBeforeDelivery) {
|
||||||
|
myReloadResourceBeforeDelivery = theReloadResourceBeforeDelivery;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,11 +23,12 @@ package ca.uhn.fhir.jpa.subscription;
|
||||||
import ca.uhn.fhir.context.ConfigurationException;
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
|
import ca.uhn.fhir.jpa.config.BaseConfig;
|
||||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails;
|
import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.util.JpaConstants;
|
import ca.uhn.fhir.jpa.util.JpaConstants;
|
||||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
|
@ -48,6 +49,7 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.core.task.AsyncTaskExecutor;
|
||||||
import org.springframework.messaging.MessageHandler;
|
import org.springframework.messaging.MessageHandler;
|
||||||
import org.springframework.messaging.SubscribableChannel;
|
import org.springframework.messaging.SubscribableChannel;
|
||||||
import org.springframework.messaging.support.ExecutorSubscribableChannel;
|
import org.springframework.messaging.support.ExecutorSubscribableChannel;
|
||||||
|
@ -92,8 +94,11 @@ public abstract class BaseSubscriptionInterceptor<S extends IBaseResource> exten
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
@Qualifier("myEventDefinitionDaoR4")
|
@Qualifier("myEventDefinitionDaoR4")
|
||||||
private IFhirResourceDao<org.hl7.fhir.r4.model.EventDefinition> myEventDefinitionDaoR4;
|
private IFhirResourceDao<org.hl7.fhir.r4.model.EventDefinition> myEventDefinitionDaoR4;
|
||||||
@Autowired
|
@Autowired()
|
||||||
private PlatformTransactionManager myTxManager;
|
private PlatformTransactionManager myTxManager;
|
||||||
|
@Autowired
|
||||||
|
@Qualifier(BaseConfig.TASK_EXECUTOR_NAME)
|
||||||
|
private AsyncTaskExecutor myAsyncTaskExecutor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -364,6 +369,11 @@ public abstract class BaseSubscriptionInterceptor<S extends IBaseResource> exten
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public void setAsyncTaskExecutorForUnitTest(AsyncTaskExecutor theAsyncTaskExecutor) {
|
||||||
|
myAsyncTaskExecutor = theAsyncTaskExecutor;
|
||||||
|
}
|
||||||
|
|
||||||
public void setFhirContext(FhirContext theCtx) {
|
public void setFhirContext(FhirContext theCtx) {
|
||||||
myCtx = theCtx;
|
myCtx = theCtx;
|
||||||
}
|
}
|
||||||
|
@ -455,7 +465,7 @@ public abstract class BaseSubscriptionInterceptor<S extends IBaseResource> exten
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mySubscriptionActivatingSubscriber == null) {
|
if (mySubscriptionActivatingSubscriber == null) {
|
||||||
mySubscriptionActivatingSubscriber = new SubscriptionActivatingSubscriber(getSubscriptionDao(), getChannelType(), this, myTxManager);
|
mySubscriptionActivatingSubscriber = new SubscriptionActivatingSubscriber(getSubscriptionDao(), getChannelType(), this, myTxManager, myAsyncTaskExecutor);
|
||||||
}
|
}
|
||||||
|
|
||||||
registerSubscriptionCheckingSubscriber();
|
registerSubscriptionCheckingSubscriber();
|
||||||
|
|
|
@ -26,7 +26,6 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
import org.hl7.fhir.r4.model.Subscription;
|
import org.hl7.fhir.r4.model.Subscription;
|
||||||
import org.springframework.messaging.MessageHandler;
|
import org.springframework.messaging.MessageHandler;
|
||||||
import org.springframework.messaging.MessagingException;
|
|
||||||
|
|
||||||
public abstract class BaseSubscriptionSubscriber implements MessageHandler {
|
public abstract class BaseSubscriptionSubscriber implements MessageHandler {
|
||||||
|
|
||||||
|
@ -60,14 +59,6 @@ public abstract class BaseSubscriptionSubscriber implements MessageHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does this subscription type (e.g. rest hook, websocket, etc) apply to this interceptor?
|
|
||||||
*/
|
|
||||||
protected boolean subscriptionTypeApplies(IBaseResource theSubscription) {
|
|
||||||
FhirContext ctx = mySubscriptionDao.getContext();
|
|
||||||
return subscriptionTypeApplies(ctx, theSubscription);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does this subscription type (e.g. rest hook, websocket, etc) apply to this interceptor?
|
* Does this subscription type (e.g. rest hook, websocket, etc) apply to this interceptor?
|
||||||
*/
|
*/
|
||||||
|
@ -80,10 +71,12 @@ public abstract class BaseSubscriptionSubscriber implements MessageHandler {
|
||||||
* Does this subscription type (e.g. rest hook, websocket, etc) apply to this interceptor?
|
* Does this subscription type (e.g. rest hook, websocket, etc) apply to this interceptor?
|
||||||
*/
|
*/
|
||||||
static boolean subscriptionTypeApplies(FhirContext theCtx, IBaseResource theSubscription, Subscription.SubscriptionChannelType theChannelType) {
|
static boolean subscriptionTypeApplies(FhirContext theCtx, IBaseResource theSubscription, Subscription.SubscriptionChannelType theChannelType) {
|
||||||
IPrimitiveType<?> status = theCtx.newTerser().getSingleValueOrNull(theSubscription, BaseSubscriptionInterceptor.SUBSCRIPTION_TYPE, IPrimitiveType.class);
|
IPrimitiveType<?> subscriptionType = theCtx.newTerser().getSingleValueOrNull(theSubscription, BaseSubscriptionInterceptor.SUBSCRIPTION_TYPE, IPrimitiveType.class);
|
||||||
boolean subscriptionTypeApplies = false;
|
boolean subscriptionTypeApplies = false;
|
||||||
if (theChannelType.toCode().equals(status.getValueAsString())) {
|
if (subscriptionType != null) {
|
||||||
subscriptionTypeApplies = true;
|
if (theChannelType.toCode().equals(subscriptionType.getValueAsString())) {
|
||||||
|
subscriptionTypeApplies = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return subscriptionTypeApplies;
|
return subscriptionTypeApplies;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,13 +23,19 @@ package ca.uhn.fhir.jpa.subscription;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
|
import ca.uhn.fhir.util.SubscriptionUtil;
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
import org.hl7.fhir.r4.model.Subscription;
|
import org.hl7.fhir.r4.model.Subscription;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.core.task.AsyncTaskExecutor;
|
||||||
import org.springframework.messaging.MessagingException;
|
import org.springframework.messaging.MessagingException;
|
||||||
|
import org.springframework.scheduling.TaskScheduler;
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
import org.springframework.transaction.TransactionStatus;
|
import org.springframework.transaction.TransactionStatus;
|
||||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||||
|
@ -37,24 +43,33 @@ import org.springframework.transaction.support.TransactionSynchronizationAdapter
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public class SubscriptionActivatingSubscriber {
|
public class SubscriptionActivatingSubscriber {
|
||||||
|
private static boolean ourWaitForSubscriptionActivationSynchronouslyForUnitTest;
|
||||||
private final IFhirResourceDao mySubscriptionDao;
|
private final IFhirResourceDao mySubscriptionDao;
|
||||||
private final BaseSubscriptionInterceptor mySubscriptionInterceptor;
|
private final BaseSubscriptionInterceptor mySubscriptionInterceptor;
|
||||||
private final PlatformTransactionManager myTransactionManager;
|
private final PlatformTransactionManager myTransactionManager;
|
||||||
|
private final AsyncTaskExecutor myTaskExecutor;
|
||||||
private Logger ourLog = LoggerFactory.getLogger(SubscriptionActivatingSubscriber.class);
|
private Logger ourLog = LoggerFactory.getLogger(SubscriptionActivatingSubscriber.class);
|
||||||
private FhirContext myCtx;
|
private FhirContext myCtx;
|
||||||
private Subscription.SubscriptionChannelType myChannelType;
|
private Subscription.SubscriptionChannelType myChannelType;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
public SubscriptionActivatingSubscriber(IFhirResourceDao<? extends IBaseResource> theSubscriptionDao, Subscription.SubscriptionChannelType theChannelType, BaseSubscriptionInterceptor theSubscriptionInterceptor, PlatformTransactionManager theTransactionManager) {
|
public SubscriptionActivatingSubscriber(IFhirResourceDao<? extends IBaseResource> theSubscriptionDao, Subscription.SubscriptionChannelType theChannelType, BaseSubscriptionInterceptor theSubscriptionInterceptor, PlatformTransactionManager theTransactionManager, AsyncTaskExecutor theTaskExecutor) {
|
||||||
mySubscriptionDao = theSubscriptionDao;
|
mySubscriptionDao = theSubscriptionDao;
|
||||||
mySubscriptionInterceptor = theSubscriptionInterceptor;
|
mySubscriptionInterceptor = theSubscriptionInterceptor;
|
||||||
myChannelType = theChannelType;
|
myChannelType = theChannelType;
|
||||||
myCtx = theSubscriptionDao.getContext();
|
myCtx = theSubscriptionDao.getContext();
|
||||||
myTransactionManager = theTransactionManager;
|
myTransactionManager = theTransactionManager;
|
||||||
|
myTaskExecutor = theTaskExecutor;
|
||||||
|
Validate.notNull(theTaskExecutor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void activateAndRegisterSubscriptionIfRequired(final IBaseResource theSubscription) {
|
public void activateAndRegisterSubscriptionIfRequired(final IBaseResource theSubscription) {
|
||||||
|
@ -70,14 +85,40 @@ public class SubscriptionActivatingSubscriber {
|
||||||
final String activeStatus = Subscription.SubscriptionStatus.ACTIVE.toCode();
|
final String activeStatus = Subscription.SubscriptionStatus.ACTIVE.toCode();
|
||||||
if (requestedStatus.equals(statusString)) {
|
if (requestedStatus.equals(statusString)) {
|
||||||
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||||
|
/*
|
||||||
|
* If we're in a transaction, we don't want to try and change the status from
|
||||||
|
* requested to active within the same transaction because it's too late by
|
||||||
|
* the time we get here to make modifications to the payload.
|
||||||
|
*
|
||||||
|
* So, we register a synchronization, meaning that when the transaction is
|
||||||
|
* finished, we'll schedule a task to do this in a separate worker thread
|
||||||
|
* to avoid any possibility of conflict.
|
||||||
|
*/
|
||||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
|
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void afterCommit() {
|
public void afterCommit() {
|
||||||
activateSubscription(status, activeStatus, theSubscription, requestedStatus);
|
Future<?> activationFuture = myTaskExecutor.submit(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
activateSubscription(activeStatus, theSubscription, requestedStatus);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we're running in a unit test, it's nice to be predictable in
|
||||||
|
* terms of order... In the real world it's a recipe for deadlocks
|
||||||
|
*/
|
||||||
|
if (ourWaitForSubscriptionActivationSynchronouslyForUnitTest) {
|
||||||
|
try {
|
||||||
|
activationFuture.get(5, TimeUnit.SECONDS);
|
||||||
|
} catch (Exception e) {
|
||||||
|
ourLog.error("Failed to activate subscription", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
activateSubscription(status, activeStatus, theSubscription, requestedStatus);
|
activateSubscription(activeStatus, theSubscription, requestedStatus);
|
||||||
}
|
}
|
||||||
} else if (activeStatus.equals(statusString)) {
|
} else if (activeStatus.equals(statusString)) {
|
||||||
if (!mySubscriptionInterceptor.hasSubscription(theSubscription.getIdElement())) {
|
if (!mySubscriptionInterceptor.hasSubscription(theSubscription.getIdElement())) {
|
||||||
|
@ -92,13 +133,21 @@ public class SubscriptionActivatingSubscriber {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void activateSubscription(IPrimitiveType<?> theStatus, String theActiveStatus, IBaseResource theSubscription, String theRequestedStatus) {
|
private void activateSubscription(String theActiveStatus, final IBaseResource theSubscription, String theRequestedStatus) {
|
||||||
theStatus.setValueAsString(theActiveStatus);
|
IBaseResource subscription = mySubscriptionDao.read(theSubscription.getIdElement());
|
||||||
ourLog.info("Activating and registering subscription {} from status {} to {}", theSubscription.getIdElement().toUnqualified().getValue(), theRequestedStatus, theActiveStatus);
|
|
||||||
mySubscriptionDao.update(theSubscription);
|
|
||||||
mySubscriptionInterceptor.registerSubscription(theSubscription.getIdElement(), theSubscription);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
ourLog.info("Activating and registering subscription {} from status {} to {}", subscription.getIdElement().toUnqualified().getValue(), theRequestedStatus, theActiveStatus);
|
||||||
|
try {
|
||||||
|
SubscriptionUtil.setStatus(myCtx, subscription, theActiveStatus);
|
||||||
|
mySubscriptionDao.update(subscription);
|
||||||
|
mySubscriptionInterceptor.registerSubscription(subscription.getIdElement(), subscription);
|
||||||
|
} catch (final UnprocessableEntityException e) {
|
||||||
|
ourLog.info("Changing status of {} to ERROR", subscription.getIdElement());
|
||||||
|
SubscriptionUtil.setStatus(myCtx, subscription, "error");
|
||||||
|
SubscriptionUtil.setReason(myCtx, subscription, e.getMessage());
|
||||||
|
mySubscriptionDao.update(subscription);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void handleMessage(RestOperationTypeEnum theOperationType, IIdType theId, final IBaseResource theSubscription) throws MessagingException {
|
public void handleMessage(RestOperationTypeEnum theOperationType, IIdType theId, final IBaseResource theSubscription) throws MessagingException {
|
||||||
|
|
||||||
|
@ -125,4 +174,9 @@ public class SubscriptionActivatingSubscriber {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public static void setWaitForSubscriptionActivationSynchronouslyForUnitTest(boolean theWaitForSubscriptionActivationSynchronouslyForUnitTest) {
|
||||||
|
ourWaitForSubscriptionActivationSynchronouslyForUnitTest = theWaitForSubscriptionActivationSynchronouslyForUnitTest;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,25 +102,22 @@ public class SubscriptionCheckingSubscriber extends BaseSubscriptionSubscriber {
|
||||||
|
|
||||||
IBundleProvider results = performSearch(criteria);
|
IBundleProvider results = performSearch(criteria);
|
||||||
|
|
||||||
ourLog.info("Subscription check found {} results for query: {}", results.size(), criteria);
|
ourLog.debug("Subscription check found {} results for query: {}", results.size(), criteria);
|
||||||
|
|
||||||
if (results.size() == 0) {
|
if (results.size() == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// should just be one resource as it was filtered by the id
|
ourLog.debug("Found match: queueing rest-hook notification for resource: {}", id.toUnqualifiedVersionless().getValue());
|
||||||
for (IBaseResource nextBase : results.getResources(0, results.size())) {
|
|
||||||
ourLog.info("Found match: queueing rest-hook notification for resource: {}", nextBase.getIdElement());
|
|
||||||
|
|
||||||
ResourceDeliveryMessage deliveryMsg = new ResourceDeliveryMessage();
|
ResourceDeliveryMessage deliveryMsg = new ResourceDeliveryMessage();
|
||||||
deliveryMsg.setPayload(getContext(), nextBase);
|
deliveryMsg.setPayload(getContext(), msg.getNewPayload(getContext()));
|
||||||
deliveryMsg.setSubscription(nextSubscription);
|
deliveryMsg.setSubscription(nextSubscription);
|
||||||
deliveryMsg.setOperationType(msg.getOperationType());
|
deliveryMsg.setOperationType(msg.getOperationType());
|
||||||
deliveryMsg.setPayloadId(msg.getId(getContext()));
|
deliveryMsg.setPayloadId(msg.getId(getContext()));
|
||||||
|
|
||||||
ResourceDeliveryJsonMessage wrappedMsg = new ResourceDeliveryJsonMessage(deliveryMsg);
|
ResourceDeliveryJsonMessage wrappedMsg = new ResourceDeliveryJsonMessage(deliveryMsg);
|
||||||
getSubscriptionInterceptor().getDeliveryChannel().send(wrappedMsg);
|
getSubscriptionInterceptor().getDeliveryChannel().send(wrappedMsg);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ package ca.uhn.fhir.jpa.subscription.email;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
@ -95,7 +95,6 @@ public class JavaMailEmailSender implements IEmailSender {
|
||||||
@Override
|
@Override
|
||||||
public void send(EmailDetails theDetails) {
|
public void send(EmailDetails theDetails) {
|
||||||
String subscriptionId = theDetails.getSubscription().toUnqualifiedVersionless().getValue();
|
String subscriptionId = theDetails.getSubscription().toUnqualifiedVersionless().getValue();
|
||||||
ourLog.info("Sending email for subscription {} to recipients: {}", subscriptionId, theDetails.getTo());
|
|
||||||
StopWatch sw = new StopWatch();
|
StopWatch sw = new StopWatch();
|
||||||
|
|
||||||
StringTemplateResolver templateResolver = new StringTemplateResolver();
|
StringTemplateResolver templateResolver = new StringTemplateResolver();
|
||||||
|
@ -116,15 +115,18 @@ public class JavaMailEmailSender implements IEmailSender {
|
||||||
|
|
||||||
MimeMessage email = mySender.createMimeMessage();
|
MimeMessage email = mySender.createMimeMessage();
|
||||||
|
|
||||||
|
String from = trim(theDetails.getFrom());
|
||||||
|
ourLog.info("Sending email for subscription {} from [{}] to recipients: [{}]", subscriptionId, from, theDetails.getTo());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
email.setFrom(trim(theDetails.getFrom()));
|
email.setFrom(from);
|
||||||
email.setRecipients(Message.RecipientType.TO, toTrimmedCommaSeparatedString(theDetails.getTo()));
|
email.setRecipients(Message.RecipientType.TO, toTrimmedCommaSeparatedString(theDetails.getTo()));
|
||||||
email.setSubject(subject);
|
email.setSubject(subject);
|
||||||
email.setText(body);
|
email.setText(body);
|
||||||
email.setSentDate(new Date());
|
email.setSentDate(new Date());
|
||||||
email.addHeader("X-FHIR-Subscription", subscriptionId);
|
email.addHeader("X-FHIR-Subscription", subscriptionId);
|
||||||
} catch (MessagingException e) {
|
} catch (MessagingException e) {
|
||||||
throw new InternalErrorException("Failed to create email messaage", e);
|
throw new InternalErrorException("Failed to create email message", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
mySender.send(email);
|
mySender.send(email);
|
||||||
|
|
|
@ -47,7 +47,7 @@ import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.dao.data.*;
|
import ca.uhn.fhir.jpa.dao.data.*;
|
||||||
import ca.uhn.fhir.jpa.entity.*;
|
import ca.uhn.fhir.jpa.entity.*;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
|
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
|
||||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
import ca.uhn.fhir.util.ObjectUtil;
|
import ca.uhn.fhir.util.ObjectUtil;
|
||||||
|
|
|
@ -7,7 +7,7 @@ import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
|
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
|
||||||
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
|
|
|
@ -7,7 +7,7 @@ import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
|
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
|
||||||
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
package ca.uhn.fhir.jpa.util;
|
package ca.uhn.fhir.jpa.util;
|
||||||
|
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* #%L
|
* #%L
|
||||||
* HAPI FHIR JPA Server
|
* HAPI FHIR JPA Server
|
||||||
|
@ -24,91 +20,10 @@ import java.util.Date;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class StopWatch {
|
/**
|
||||||
|
* @deprecated Use {@link ca.uhn.fhir.util.StopWatch} instead
|
||||||
private long myStarted = System.currentTimeMillis();
|
*/
|
||||||
|
@Deprecated
|
||||||
/**
|
public class StopWatch extends ca.uhn.fhir.util.StopWatch {
|
||||||
* Constructor
|
// this just exists since existing code may depend on it
|
||||||
*/
|
|
||||||
public StopWatch() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
public StopWatch(Date theNow) {
|
|
||||||
myStarted = theNow.getTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getMillisAndRestart() {
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
long retVal = now - myStarted;
|
|
||||||
myStarted = now;
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getMillis() {
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
long retVal = now - myStarted;
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getMillis(Date theNow) {
|
|
||||||
long retVal = theNow.getTime() - myStarted;
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Date getStartedDate() {
|
|
||||||
return new Date(myStarted);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Formats value in the format [DD d ]HH:mm:ss.SSSS
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return formatMillis(getMillis());
|
|
||||||
}
|
|
||||||
|
|
||||||
static public String formatMillis(long val) {
|
|
||||||
StringBuilder buf = new StringBuilder(20);
|
|
||||||
if (val >= DateUtils.MILLIS_PER_DAY) {
|
|
||||||
long days = val / DateUtils.MILLIS_PER_DAY;
|
|
||||||
append(buf, "", 1, days);
|
|
||||||
if (days > 1) {
|
|
||||||
buf.append(" days ");
|
|
||||||
} else if (days == 1) {
|
|
||||||
buf.append(" day ");
|
|
||||||
}
|
|
||||||
append(buf, "", 2, ((val % DateUtils.MILLIS_PER_DAY) / DateUtils.MILLIS_PER_HOUR));
|
|
||||||
} else {
|
|
||||||
append(buf, "", 2, ((val % DateUtils.MILLIS_PER_DAY) / DateUtils.MILLIS_PER_HOUR));
|
|
||||||
}
|
|
||||||
append(buf, ":", 2, ((val % DateUtils.MILLIS_PER_HOUR) / DateUtils.MILLIS_PER_MINUTE));
|
|
||||||
append(buf, ":", 2, ((val % DateUtils.MILLIS_PER_MINUTE) / DateUtils.MILLIS_PER_SECOND));
|
|
||||||
append(buf, ".", 3, (val % DateUtils.MILLIS_PER_SECOND));
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Append a right-aligned and zero-padded numeric value to a `StringBuilder`. */
|
|
||||||
static private void append(StringBuilder tgt, String pfx, int dgt, long val) {
|
|
||||||
tgt.append(pfx);
|
|
||||||
if (dgt > 1) {
|
|
||||||
int pad = (dgt - 1);
|
|
||||||
for (long xa = val; xa > 9 && pad > 0; xa /= 10) {
|
|
||||||
pad--;
|
|
||||||
}
|
|
||||||
for (int xa = 0; xa < pad; xa++) {
|
|
||||||
tgt.append('0');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tgt.append(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMillisPerOperation(int theNumOperations) {
|
|
||||||
return (int)(((double) getMillis()) / Math.max(1.0, theNumOperations));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ public class SubscriptionsRequireManualActivationInterceptorDstu2 extends Server
|
||||||
|
|
||||||
if (newStatus == null) {
|
if (newStatus == null) {
|
||||||
String actualCode = subscription.getStatusElement().getValueAsString();
|
String actualCode = subscription.getStatusElement().getValueAsString();
|
||||||
throw new UnprocessableEntityException("Can not " + theOperation.getCode() + " resource: Subscription.status must be populated" + ((isNotBlank(actualCode)) ? " (invalid value " + actualCode + ")" : ""));
|
throw new UnprocessableEntityException("Can not " + theOperation.getCode() + " resource: Subscription.status must be populated on this server" + ((isNotBlank(actualCode)) ? " (invalid value " + actualCode + ")" : ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theOldResourceOrNull != null) {
|
if (theOldResourceOrNull != null) {
|
||||||
|
@ -108,7 +108,7 @@ public class SubscriptionsRequireManualActivationInterceptorDstu2 extends Server
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theSubscription.getStatus() == null) {
|
if (theSubscription.getStatus() == null) {
|
||||||
throw new UnprocessableEntityException("Can not " + theOperation.getCode().toLowerCase() + " resource: Subscription.status must be populated");
|
throw new UnprocessableEntityException("Can not " + theOperation.getCode().toLowerCase() + " resource: Subscription.status must be populated on this server");
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new UnprocessableEntityException("Subscription.status must be '" + SubscriptionStatusEnum.OFF.getCode() + "' or '" + SubscriptionStatusEnum.REQUESTED.getCode() + "' on a newly created subscription");
|
throw new UnprocessableEntityException("Subscription.status must be '" + SubscriptionStatusEnum.OFF.getCode() + "' or '" + SubscriptionStatusEnum.REQUESTED.getCode() + "' on a newly created subscription");
|
||||||
|
|
|
@ -74,7 +74,7 @@ public class SubscriptionsRequireManualActivationInterceptorDstu3 extends Server
|
||||||
|
|
||||||
if (newStatus == null) {
|
if (newStatus == null) {
|
||||||
String actualCode = subscription.getStatusElement().getValueAsString();
|
String actualCode = subscription.getStatusElement().getValueAsString();
|
||||||
throw new UnprocessableEntityException("Can not " + theOperation.getCode() + " resource: Subscription.status must be populated" + ((isNotBlank(actualCode)) ? " (invalid value " + actualCode + ")" : ""));
|
throw new UnprocessableEntityException("Can not " + theOperation.getCode() + " resource: Subscription.status must be populated on this server" + ((isNotBlank(actualCode)) ? " (invalid value " + actualCode + ")" : ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theOldResourceOrNull != null) {
|
if (theOldResourceOrNull != null) {
|
||||||
|
@ -108,7 +108,7 @@ public class SubscriptionsRequireManualActivationInterceptorDstu3 extends Server
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theSubscription.getStatus() == null) {
|
if (theSubscription.getStatus() == null) {
|
||||||
throw new UnprocessableEntityException("Can not " + theOperation.getCode().toLowerCase() + " resource: Subscription.status must be populated");
|
throw new UnprocessableEntityException("Can not " + theOperation.getCode().toLowerCase() + " resource: Subscription.status must be populated on this server");
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new UnprocessableEntityException("Subscription.status must be '" + SubscriptionStatus.OFF.toCode() + "' or '" + SubscriptionStatus.REQUESTED.toCode() + "' on a newly created subscription");
|
throw new UnprocessableEntityException("Subscription.status must be '" + SubscriptionStatus.OFF.toCode() + "' or '" + SubscriptionStatus.REQUESTED.toCode() + "' on a newly created subscription");
|
||||||
|
|
|
@ -74,7 +74,7 @@ public class SubscriptionsRequireManualActivationInterceptorR4 extends ServerOpe
|
||||||
|
|
||||||
if (newStatus == null) {
|
if (newStatus == null) {
|
||||||
String actualCode = subscription.getStatusElement().getValueAsString();
|
String actualCode = subscription.getStatusElement().getValueAsString();
|
||||||
throw new UnprocessableEntityException("Can not " + theOperation.getCode() + " resource: Subscription.status must be populated" + ((isNotBlank(actualCode)) ? " (invalid value " + actualCode + ")" : ""));
|
throw new UnprocessableEntityException("Can not " + theOperation.getCode() + " resource: Subscription.status must be populated on this server" + ((isNotBlank(actualCode)) ? " (invalid value " + actualCode + ")" : ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theOldResourceOrNull != null) {
|
if (theOldResourceOrNull != null) {
|
||||||
|
@ -108,7 +108,7 @@ public class SubscriptionsRequireManualActivationInterceptorR4 extends ServerOpe
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theSubscription.getStatus() == null) {
|
if (theSubscription.getStatus() == null) {
|
||||||
throw new UnprocessableEntityException("Can not " + theOperation.getCode().toLowerCase() + " resource: Subscription.status must be populated");
|
throw new UnprocessableEntityException("Can not " + theOperation.getCode().toLowerCase() + " resource: Subscription.status must be populated on this server");
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new UnprocessableEntityException("Subscription.status must be '" + SubscriptionStatus.OFF.toCode() + "' or '" + SubscriptionStatus.REQUESTED.toCode() + "' on a newly created subscription");
|
throw new UnprocessableEntityException("Subscription.status must be '" + SubscriptionStatus.OFF.toCode() + "' or '" + SubscriptionStatus.REQUESTED.toCode() + "' on a newly created subscription");
|
||||||
|
|
|
@ -47,7 +47,7 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Connection getConnection() throws SQLException {
|
public Connection getConnection() {
|
||||||
ConnectionWrapper retVal;
|
ConnectionWrapper retVal;
|
||||||
try {
|
try {
|
||||||
retVal = new ConnectionWrapper(super.getConnection());
|
retVal = new ConnectionWrapper(super.getConnection());
|
||||||
|
|
|
@ -6,7 +6,7 @@ import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test;
|
||||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||||
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
|
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
|
||||||
import ca.uhn.fhir.jpa.term.VersionIndependentConcept;
|
import ca.uhn.fhir.jpa.term.VersionIndependentConcept;
|
||||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
|
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
|
@ -34,7 +34,6 @@ import org.springframework.transaction.support.TransactionTemplate;
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
@ -158,7 +157,7 @@ public abstract class BaseJpaTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<IIdType> toUnqualifiedVersionlessIds(IBundleProvider theFound) {
|
protected List<IIdType> toUnqualifiedVersionlessIds(IBundleProvider theFound) {
|
||||||
List<IIdType> retVal = new ArrayList<IIdType>();
|
List<IIdType> retVal = new ArrayList<>();
|
||||||
Integer size = theFound.size();
|
Integer size = theFound.size();
|
||||||
StopWatch sw = new StopWatch();
|
StopWatch sw = new StopWatch();
|
||||||
while (size == null) {
|
while (size == null) {
|
||||||
|
@ -171,6 +170,7 @@ public abstract class BaseJpaTest {
|
||||||
} catch (InterruptedException theE) {
|
} catch (InterruptedException theE) {
|
||||||
//ignore
|
//ignore
|
||||||
}
|
}
|
||||||
|
size = theFound.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLog.info("Found {} results", size);
|
ourLog.info("Found {} results", size);
|
||||||
|
|
|
@ -75,6 +75,9 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
|
||||||
@Qualifier("myDiagnosticReportDaoDstu2")
|
@Qualifier("myDiagnosticReportDaoDstu2")
|
||||||
protected IFhirResourceDao<DiagnosticReport> myDiagnosticReportDao;
|
protected IFhirResourceDao<DiagnosticReport> myDiagnosticReportDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@Qualifier("myBinaryDaoDstu2")
|
||||||
|
protected IFhirResourceDao<Binary> myBinaryDao;
|
||||||
|
@Autowired
|
||||||
@Qualifier("myEncounterDaoDstu2")
|
@Qualifier("myEncounterDaoDstu2")
|
||||||
protected IFhirResourceDao<Encounter> myEncounterDao;
|
protected IFhirResourceDao<Encounter> myEncounterDao;
|
||||||
// @PersistenceContext()
|
// @PersistenceContext()
|
||||||
|
|
|
@ -19,9 +19,9 @@ import ca.uhn.fhir.util.TestUtil;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.internal.util.collections.ListUtil;
|
import org.mockito.internal.util.collections.ListUtil;
|
||||||
import org.thymeleaf.util.ListUtils;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -53,90 +53,6 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testOverrideAndDisableBuiltInSearchParametersWithOverridingEnabled() {
|
|
||||||
myDaoConfig.setDefaultSearchParamsCanBeOverridden(true);
|
|
||||||
|
|
||||||
SearchParameter memberSp = new SearchParameter();
|
|
||||||
memberSp.setCode("member");
|
|
||||||
memberSp.setBase(ResourceTypeEnum.GROUP);
|
|
||||||
memberSp.setType(SearchParamTypeEnum.REFERENCE);
|
|
||||||
memberSp.setXpath("Group.member.entity");
|
|
||||||
memberSp.setXpathUsage(XPathUsageTypeEnum.NORMAL);
|
|
||||||
memberSp.setStatus(ConformanceResourceStatusEnum.RETIRED);
|
|
||||||
mySearchParameterDao.create(memberSp, mySrd);
|
|
||||||
|
|
||||||
SearchParameter identifierSp = new SearchParameter();
|
|
||||||
identifierSp.setCode("identifier");
|
|
||||||
identifierSp.setBase(ResourceTypeEnum.GROUP);
|
|
||||||
identifierSp.setType(SearchParamTypeEnum.TOKEN);
|
|
||||||
identifierSp.setXpath("Group.identifier");
|
|
||||||
identifierSp.setXpathUsage(XPathUsageTypeEnum.NORMAL);
|
|
||||||
identifierSp.setStatus(ConformanceResourceStatusEnum.RETIRED);
|
|
||||||
mySearchParameterDao.create(identifierSp, mySrd);
|
|
||||||
|
|
||||||
mySearchParamRegsitry.forceRefresh();
|
|
||||||
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().addGiven("G");
|
|
||||||
IIdType pid = myPatientDao.create(p).getId().toUnqualifiedVersionless();
|
|
||||||
|
|
||||||
Group g = new Group();
|
|
||||||
g.addIdentifier().setSystem("urn:foo").setValue("bar");
|
|
||||||
g.addMember().getEntity().setReference(pid);
|
|
||||||
myGroupDao.create(g);
|
|
||||||
|
|
||||||
assertThat(myResourceLinkDao.findAll(), empty());
|
|
||||||
assertThat(ListUtil.filter(myResourceIndexedSearchParamTokenDao.findAll(), new ListUtil.Filter<ResourceIndexedSearchParamToken>() {
|
|
||||||
@Override
|
|
||||||
public boolean isOut(ResourceIndexedSearchParamToken object) {
|
|
||||||
return !object.getResourceType().equals("Group") || object.isMissing();
|
|
||||||
}
|
|
||||||
}), empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testOverrideAndDisableBuiltInSearchParametersWithOverridingDisabled() {
|
|
||||||
myDaoConfig.setDefaultSearchParamsCanBeOverridden(false);
|
|
||||||
|
|
||||||
SearchParameter memberSp = new SearchParameter();
|
|
||||||
memberSp.setCode("member");
|
|
||||||
memberSp.setBase(ResourceTypeEnum.GROUP);
|
|
||||||
memberSp.setType(SearchParamTypeEnum.REFERENCE);
|
|
||||||
memberSp.setXpath("Group.member.entity");
|
|
||||||
memberSp.setXpathUsage(XPathUsageTypeEnum.NORMAL);
|
|
||||||
memberSp.setStatus(ConformanceResourceStatusEnum.RETIRED);
|
|
||||||
mySearchParameterDao.create(memberSp, mySrd);
|
|
||||||
|
|
||||||
SearchParameter identifierSp = new SearchParameter();
|
|
||||||
identifierSp.setCode("identifier");
|
|
||||||
identifierSp.setBase(ResourceTypeEnum.GROUP);
|
|
||||||
identifierSp.setType(SearchParamTypeEnum.TOKEN);
|
|
||||||
identifierSp.setXpath("Group.identifier");
|
|
||||||
identifierSp.setXpathUsage(XPathUsageTypeEnum.NORMAL);
|
|
||||||
identifierSp.setStatus(ConformanceResourceStatusEnum.RETIRED);
|
|
||||||
mySearchParameterDao.create(identifierSp, mySrd);
|
|
||||||
|
|
||||||
mySearchParamRegsitry.forceRefresh();
|
|
||||||
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().addGiven("G");
|
|
||||||
IIdType pid = myPatientDao.create(p).getId().toUnqualifiedVersionless();
|
|
||||||
|
|
||||||
Group g = new Group();
|
|
||||||
g.addIdentifier().setSystem("urn:foo").setValue("bar");
|
|
||||||
g.addMember().getEntity().setReference(pid);
|
|
||||||
myGroupDao.create(g);
|
|
||||||
|
|
||||||
assertThat(myResourceLinkDao.findAll(), not(empty()));
|
|
||||||
assertThat(ListUtil.filter(myResourceIndexedSearchParamTokenDao.findAll(), new ListUtil.Filter<ResourceIndexedSearchParamToken>() {
|
|
||||||
@Override
|
|
||||||
public boolean isOut(ResourceIndexedSearchParamToken object) {
|
|
||||||
return !object.getResourceType().equals("Group") || object.isMissing();
|
|
||||||
}
|
|
||||||
}), not(empty()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateInvalidParamInvalidResourceName() {
|
public void testCreateInvalidParamInvalidResourceName() {
|
||||||
SearchParameter fooSp = new SearchParameter();
|
SearchParameter fooSp = new SearchParameter();
|
||||||
|
@ -154,23 +70,6 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCreateInvalidParamMismatchedResourceName() {
|
|
||||||
SearchParameter fooSp = new SearchParameter();
|
|
||||||
fooSp.setBase(ResourceTypeEnum.PATIENT);
|
|
||||||
fooSp.setCode("foo");
|
|
||||||
fooSp.setType(SearchParamTypeEnum.TOKEN);
|
|
||||||
fooSp.setXpath("Patient.gender or Observation.code");
|
|
||||||
fooSp.setXpathUsage(XPathUsageTypeEnum.NORMAL);
|
|
||||||
fooSp.setStatus(ConformanceResourceStatusEnum.ACTIVE);
|
|
||||||
try {
|
|
||||||
mySearchParameterDao.create(fooSp, mySrd);
|
|
||||||
fail();
|
|
||||||
} catch (UnprocessableEntityException e) {
|
|
||||||
assertEquals("Invalid SearchParameter.expression value \"Observation.code\". All paths in a single SearchParameter must match the same resource type", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateInvalidParamNoPath() {
|
public void testCreateInvalidParamNoPath() {
|
||||||
SearchParameter fooSp = new SearchParameter();
|
SearchParameter fooSp = new SearchParameter();
|
||||||
|
@ -224,7 +123,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCustomReferenceParameter() throws Exception {
|
public void testCustomReferenceParameter() {
|
||||||
SearchParameter sp = new SearchParameter();
|
SearchParameter sp = new SearchParameter();
|
||||||
sp.setBase(ResourceTypeEnum.PATIENT);
|
sp.setBase(ResourceTypeEnum.PATIENT);
|
||||||
sp.setCode("myDoctor");
|
sp.setCode("myDoctor");
|
||||||
|
@ -234,6 +133,8 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
||||||
sp.setStatus(ConformanceResourceStatusEnum.ACTIVE);
|
sp.setStatus(ConformanceResourceStatusEnum.ACTIVE);
|
||||||
mySearchParameterDao.create(sp);
|
mySearchParameterDao.create(sp);
|
||||||
|
|
||||||
|
mySearchParamRegsitry.forceRefresh();
|
||||||
|
|
||||||
Practitioner pract = new Practitioner();
|
Practitioner pract = new Practitioner();
|
||||||
pract.setId("A");
|
pract.setId("A");
|
||||||
pract.getName().addFamily("PRACT");
|
pract.getName().addFamily("PRACT");
|
||||||
|
@ -312,6 +213,90 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOverrideAndDisableBuiltInSearchParametersWithOverridingDisabled() {
|
||||||
|
myDaoConfig.setDefaultSearchParamsCanBeOverridden(false);
|
||||||
|
|
||||||
|
SearchParameter memberSp = new SearchParameter();
|
||||||
|
memberSp.setCode("member");
|
||||||
|
memberSp.setBase(ResourceTypeEnum.GROUP);
|
||||||
|
memberSp.setType(SearchParamTypeEnum.REFERENCE);
|
||||||
|
memberSp.setXpath("Group.member.entity");
|
||||||
|
memberSp.setXpathUsage(XPathUsageTypeEnum.NORMAL);
|
||||||
|
memberSp.setStatus(ConformanceResourceStatusEnum.RETIRED);
|
||||||
|
mySearchParameterDao.create(memberSp, mySrd);
|
||||||
|
|
||||||
|
SearchParameter identifierSp = new SearchParameter();
|
||||||
|
identifierSp.setCode("identifier");
|
||||||
|
identifierSp.setBase(ResourceTypeEnum.GROUP);
|
||||||
|
identifierSp.setType(SearchParamTypeEnum.TOKEN);
|
||||||
|
identifierSp.setXpath("Group.identifier");
|
||||||
|
identifierSp.setXpathUsage(XPathUsageTypeEnum.NORMAL);
|
||||||
|
identifierSp.setStatus(ConformanceResourceStatusEnum.RETIRED);
|
||||||
|
mySearchParameterDao.create(identifierSp, mySrd);
|
||||||
|
|
||||||
|
mySearchParamRegsitry.forceRefresh();
|
||||||
|
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.addName().addGiven("G");
|
||||||
|
IIdType pid = myPatientDao.create(p).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
Group g = new Group();
|
||||||
|
g.addIdentifier().setSystem("urn:foo").setValue("bar");
|
||||||
|
g.addMember().getEntity().setReference(pid);
|
||||||
|
myGroupDao.create(g);
|
||||||
|
|
||||||
|
assertThat(myResourceLinkDao.findAll(), not(empty()));
|
||||||
|
assertThat(ListUtil.filter(myResourceIndexedSearchParamTokenDao.findAll(), new ListUtil.Filter<ResourceIndexedSearchParamToken>() {
|
||||||
|
@Override
|
||||||
|
public boolean isOut(ResourceIndexedSearchParamToken object) {
|
||||||
|
return !object.getResourceType().equals("Group") || object.isMissing();
|
||||||
|
}
|
||||||
|
}), not(empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOverrideAndDisableBuiltInSearchParametersWithOverridingEnabled() {
|
||||||
|
myDaoConfig.setDefaultSearchParamsCanBeOverridden(true);
|
||||||
|
|
||||||
|
SearchParameter memberSp = new SearchParameter();
|
||||||
|
memberSp.setCode("member");
|
||||||
|
memberSp.setBase(ResourceTypeEnum.GROUP);
|
||||||
|
memberSp.setType(SearchParamTypeEnum.REFERENCE);
|
||||||
|
memberSp.setXpath("Group.member.entity");
|
||||||
|
memberSp.setXpathUsage(XPathUsageTypeEnum.NORMAL);
|
||||||
|
memberSp.setStatus(ConformanceResourceStatusEnum.RETIRED);
|
||||||
|
mySearchParameterDao.create(memberSp, mySrd);
|
||||||
|
|
||||||
|
SearchParameter identifierSp = new SearchParameter();
|
||||||
|
identifierSp.setCode("identifier");
|
||||||
|
identifierSp.setBase(ResourceTypeEnum.GROUP);
|
||||||
|
identifierSp.setType(SearchParamTypeEnum.TOKEN);
|
||||||
|
identifierSp.setXpath("Group.identifier");
|
||||||
|
identifierSp.setXpathUsage(XPathUsageTypeEnum.NORMAL);
|
||||||
|
identifierSp.setStatus(ConformanceResourceStatusEnum.RETIRED);
|
||||||
|
mySearchParameterDao.create(identifierSp, mySrd);
|
||||||
|
|
||||||
|
mySearchParamRegsitry.forceRefresh();
|
||||||
|
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.addName().addGiven("G");
|
||||||
|
IIdType pid = myPatientDao.create(p).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
Group g = new Group();
|
||||||
|
g.addIdentifier().setSystem("urn:foo").setValue("bar");
|
||||||
|
g.addMember().getEntity().setReference(pid);
|
||||||
|
myGroupDao.create(g);
|
||||||
|
|
||||||
|
assertThat(myResourceLinkDao.findAll(), empty());
|
||||||
|
assertThat(ListUtil.filter(myResourceIndexedSearchParamTokenDao.findAll(), new ListUtil.Filter<ResourceIndexedSearchParamToken>() {
|
||||||
|
@Override
|
||||||
|
public boolean isOut(ResourceIndexedSearchParamToken object) {
|
||||||
|
return !object.getResourceType().equals("Group") || object.isMissing();
|
||||||
|
}
|
||||||
|
}), empty());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSearchForExtensionReferenceWithNonMatchingTarget() {
|
public void testSearchForExtensionReferenceWithNonMatchingTarget() {
|
||||||
SearchParameter siblingSp = new SearchParameter();
|
SearchParameter siblingSp = new SearchParameter();
|
||||||
|
@ -883,6 +868,53 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
public void testSearchForStringOnIdentifierWithSpecificSystem() {
|
||||||
|
|
||||||
|
SearchParameter fooSp = new SearchParameter();
|
||||||
|
fooSp.setBase(ResourceTypeEnum.PATIENT);
|
||||||
|
fooSp.setCode("foo");
|
||||||
|
fooSp.setType(SearchParamTypeEnum.STRING);
|
||||||
|
fooSp.setXpath("Patient.identifier.where(system = 'http://AAA').value");
|
||||||
|
fooSp.setXpathUsage(XPathUsageTypeEnum.NORMAL);
|
||||||
|
fooSp.setStatus(ConformanceResourceStatusEnum.ACTIVE);
|
||||||
|
IIdType spId = mySearchParameterDao.create(fooSp, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
|
||||||
|
mySearchParamRegsitry.forceRefresh();
|
||||||
|
|
||||||
|
Patient pat = new Patient();
|
||||||
|
pat.addIdentifier().setSystem("http://AAA").setValue("BAR678");
|
||||||
|
pat.setGender(AdministrativeGenderEnum.MALE);
|
||||||
|
IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
Patient pat2 = new Patient();
|
||||||
|
pat2.addIdentifier().setSystem("http://BBB").setValue("BAR678");
|
||||||
|
pat2.setGender(AdministrativeGenderEnum.FEMALE);
|
||||||
|
myPatientDao.create(pat2, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
SearchParameterMap map;
|
||||||
|
IBundleProvider results;
|
||||||
|
List<String> foundResources;
|
||||||
|
|
||||||
|
// Partial match
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.add("foo", new StringParam("bar"));
|
||||||
|
results = myPatientDao.search(map);
|
||||||
|
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||||
|
assertThat(foundResources, contains(patId.getValue()));
|
||||||
|
|
||||||
|
// Non match
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.add("foo", new StringParam("zzz"));
|
||||||
|
results = myPatientDao.search(map);
|
||||||
|
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||||
|
assertThat(foundResources, empty());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSearchWithCustomParam() {
|
public void testSearchWithCustomParam() {
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue