diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java
index f6c6a2e2bbc..981b67d2194 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java
@@ -70,6 +70,8 @@ import ca.uhn.fhir.model.api.IResourceBlock;
import ca.uhn.fhir.model.api.IValueSetEnumBinder;
import ca.uhn.fhir.model.api.annotation.Block;
import ca.uhn.fhir.model.api.annotation.Child;
+import ca.uhn.fhir.model.api.annotation.Compartment;
+import ca.uhn.fhir.model.api.annotation.Compartments;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.Extension;
@@ -87,7 +89,6 @@ import ca.uhn.fhir.util.ReflectionUtil;
class ModelScanner {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ModelScanner.class);
- private final Map, Class extends Annotation>> myAnnotationForwards = new HashMap, Class extends Annotation>>();
private Map, BaseRuntimeElementDefinition>> myClassToElementDefinitions = new HashMap, BaseRuntimeElementDefinition>>();
private FhirContext myContext;
private Map myIdToResourceDefinition = new HashMap();
@@ -101,7 +102,8 @@ class ModelScanner {
private Set> myVersionTypes;
- ModelScanner(FhirContext theContext, FhirVersionEnum theVersion, Map, BaseRuntimeElementDefinition>> theExistingDefinitions, Collection> theResourceTypes) throws ConfigurationException {
+ ModelScanner(FhirContext theContext, FhirVersionEnum theVersion, Map, BaseRuntimeElementDefinition>> theExistingDefinitions,
+ Collection> theResourceTypes) throws ConfigurationException {
myContext = theContext;
myVersion = theVersion;
Set> toScan;
@@ -189,7 +191,7 @@ class ModelScanner {
Map> resourceTypes = myNameToResourceType;
myVersionTypes = scanVersionPropertyFile(theDatatypes, resourceTypes, myVersion);
-
+
// toScan.add(DateDt.class);
// toScan.add(CodeDt.class);
// toScan.add(DecimalDt.class);
@@ -233,68 +235,13 @@ class ModelScanner {
}
/**
- * There are two implementations of all of the annotations (e.g. {@link Child} and
- * {@link org.hl7.fhir.instance.model.annotations.Child}) since the HL7.org ones will eventually replace the HAPI
- * ones. Annotations can't extend each other or implement interfaces or anything like that, so rather than duplicate
- * all of the annotation processing code this method just creates an interface Proxy to simulate the HAPI
- * annotations if the HL7.org ones are found instead.
+ * There are two implementations of all of the annotations (e.g. {@link Child} and {@link org.hl7.fhir.instance.model.annotations.Child}) since the HL7.org ones will eventually replace the HAPI
+ * ones. Annotations can't extend each other or implement interfaces or anything like that, so rather than duplicate all of the annotation processing code this method just creates an interface
+ * Proxy to simulate the HAPI annotations if the HL7.org ones are found instead.
*/
- @SuppressWarnings("unchecked")
- private T pullAnnotation(Class> theContainer, AnnotatedElement theTarget, Class theAnnotationType) {
-
+ private T pullAnnotation(AnnotatedElement theTarget, Class theAnnotationType) {
T retVal = theTarget.getAnnotation(theAnnotationType);
-// if (myContext.getVersion().getVersion() != FhirVersionEnum.DSTU2_HL7ORG) {
- return retVal;
-// }
-//
-// if (retVal == null) {
-// final Class extends Annotation> altAnnotationClass;
-// /*
-// * Use a cache to minimize Class.forName calls, since they are slow and expensive..
-// */
-// if (myAnnotationForwards.containsKey(theAnnotationType) == false) {
-// String sourceClassName = theAnnotationType.getName();
-// String candidateAltClassName = sourceClassName.replace("ca.uhn.fhir.model.api.annotation", "org.hl7.fhir.instance.model.annotations");
-// if (!sourceClassName.equals(candidateAltClassName)) {
-// Class> forName;
-// try {
-// forName = Class.forName(candidateAltClassName);
-// ourLog.debug("Forwarding annotation request for [{}] to class [{}]", theAnnotationType, forName);
-// } catch (ClassNotFoundException e) {
-// forName = null;
-// }
-// altAnnotationClass = (Class extends Annotation>) forName;
-// } else {
-// altAnnotationClass = null;
-// }
-// myAnnotationForwards.put(theAnnotationType, altAnnotationClass);
-// } else {
-// altAnnotationClass = myAnnotationForwards.get(theAnnotationType);
-// }
-//
-// if (altAnnotationClass == null) {
-// return null;
-// }
-//
-// final Annotation altAnnotation;
-// altAnnotation = theTarget.getAnnotation(altAnnotationClass);
-// if (altAnnotation == null) {
-// return null;
-// }
-//
-// InvocationHandler h = new InvocationHandler() {
-//
-// @Override
-// public Object invoke(Object theProxy, Method theMethod, Object[] theArgs) throws Throwable {
-// Method altMethod = altAnnotationClass.getMethod(theMethod.getName(), theMethod.getParameterTypes());
-// return altMethod.invoke(altAnnotation, theArgs);
-// }
-// };
-// retVal = (T) Proxy.newProxyInstance(theAnnotationType.getClassLoader(), new Class>[] { theAnnotationType }, h);
-//
-// }
-//
-// return retVal;
+ return retVal;
}
private void scan(Class extends IBase> theClass) throws ConfigurationException {
@@ -303,17 +250,18 @@ class ModelScanner {
return;
}
- ResourceDef resourceDefinition = pullAnnotation(theClass, theClass, ResourceDef.class);
+ ResourceDef resourceDefinition = pullAnnotation(theClass, ResourceDef.class);
if (resourceDefinition != null) {
if (!IBaseResource.class.isAssignableFrom(theClass)) {
- throw new ConfigurationException("Resource type contains a @" + ResourceDef.class.getSimpleName() + " annotation but does not implement " + IResource.class.getCanonicalName() + ": " + theClass.getCanonicalName());
+ throw new ConfigurationException(
+ "Resource type contains a @" + ResourceDef.class.getSimpleName() + " annotation but does not implement " + IResource.class.getCanonicalName() + ": " + theClass.getCanonicalName());
}
@SuppressWarnings("unchecked")
Class extends IBaseResource> resClass = (Class extends IBaseResource>) theClass;
scanResource(resClass, resourceDefinition);
}
- DatatypeDef datatypeDefinition = pullAnnotation(theClass, theClass, DatatypeDef.class);
+ DatatypeDef datatypeDefinition = pullAnnotation(theClass, DatatypeDef.class);
if (datatypeDefinition != null) {
if (ICompositeType.class.isAssignableFrom(theClass)) {
@SuppressWarnings("unchecked")
@@ -325,17 +273,19 @@ class ModelScanner {
scanPrimitiveDatatype(resClass, datatypeDefinition);
} else {
return;
-// throw new ConfigurationException("Resource type contains a @" + DatatypeDef.class.getSimpleName() + " annotation but does not implement " + IDatatype.class.getCanonicalName() + ": " + theClass.getCanonicalName());
+ // throw new ConfigurationException("Resource type contains a @" + DatatypeDef.class.getSimpleName() + " annotation but does not implement " + IDatatype.class.getCanonicalName() + ": " +
+ // theClass.getCanonicalName());
}
}
- Block blockDefinition = pullAnnotation(theClass, theClass, Block.class);
+ Block blockDefinition = pullAnnotation(theClass, Block.class);
if (blockDefinition != null) {
if (IResourceBlock.class.isAssignableFrom(theClass) || IBaseBackboneElement.class.isAssignableFrom(theClass) || IBaseDatatypeElement.class.isAssignableFrom(theClass)) {
scanBlock(theClass);
} else {
- throw new ConfigurationException("Type contains a @" + Block.class.getSimpleName() + " annotation but does not implement " + IResourceBlock.class.getCanonicalName() + ": " + theClass.getCanonicalName());
+ throw new ConfigurationException(
+ "Type contains a @" + Block.class.getSimpleName() + " annotation but does not implement " + IResourceBlock.class.getCanonicalName() + ": " + theClass.getCanonicalName());
}
}
@@ -364,8 +314,8 @@ class ModelScanner {
RuntimeCompositeDatatypeDefinition resourceDef;
if (theClass.equals(ExtensionDt.class)) {
resourceDef = new RuntimeExtensionDtDefinition(theDatatypeDefinition, theClass, true);
-// } else if (IBaseMetaType.class.isAssignableFrom(theClass)) {
-// resourceDef = new RuntimeMetaDefinition(theDatatypeDefinition, theClass, isStandardType(theClass));
+ // } else if (IBaseMetaType.class.isAssignableFrom(theClass)) {
+ // resourceDef = new RuntimeMetaDefinition(theDatatypeDefinition, theClass, isStandardType(theClass));
} else {
resourceDef = new RuntimeCompositeDatatypeDefinition(theDatatypeDefinition, theClass, isStandardType(theClass));
}
@@ -429,7 +379,8 @@ class ModelScanner {
}
@SuppressWarnings("unchecked")
- private void scanCompositeElementForChildren(Class extends IBase> theClass, Set elementNames, TreeMap theOrderToElementDef, TreeMap theOrderToExtensionDef) {
+ private void scanCompositeElementForChildren(Class extends IBase> theClass, Set elementNames, TreeMap theOrderToElementDef,
+ TreeMap theOrderToExtensionDef) {
int baseElementOrder = theOrderToElementDef.isEmpty() ? 0 : theOrderToElementDef.lastEntry().getKey() + 1;
for (Field next : theClass.getDeclaredFields()) {
@@ -439,16 +390,16 @@ class ModelScanner {
continue;
}
- Child childAnnotation = pullAnnotation(theClass, next, Child.class);
+ Child childAnnotation = pullAnnotation(next, Child.class);
if (childAnnotation == null) {
ourLog.trace("Ignoring non @Child field {} on target type {}", next.getName(), theClass);
continue;
}
- Description descriptionAnnotation = pullAnnotation(theClass, next, Description.class);
+ Description descriptionAnnotation = pullAnnotation(next, Description.class);
TreeMap orderMap = theOrderToElementDef;
- Extension extensionAttr = pullAnnotation(theClass, next, Extension.class);
+ Extension extensionAttr = pullAnnotation(next, Extension.class);
if (extensionAttr != null) {
orderMap = theOrderToExtensionDef;
}
@@ -471,8 +422,8 @@ class ModelScanner {
}
}
if (order == Child.REPLACE_PARENT) {
- throw new ConfigurationException("Field " + next.getName() + "' on target type " + theClass.getSimpleName() + " has order() of REPLACE_PARENT (" + Child.REPLACE_PARENT + ") but no parent element with extension URL " + extensionAttr.url() + " could be found on type "
- + next.getDeclaringClass().getSimpleName());
+ throw new ConfigurationException("Field " + next.getName() + "' on target type " + theClass.getSimpleName() + " has order() of REPLACE_PARENT (" + Child.REPLACE_PARENT
+ + ") but no parent element with extension URL " + extensionAttr.url() + " could be found on type " + next.getDeclaringClass().getSimpleName());
}
} else {
@@ -487,8 +438,8 @@ class ModelScanner {
}
}
if (order == Child.REPLACE_PARENT) {
- throw new ConfigurationException("Field " + next.getName() + "' on target type " + theClass.getSimpleName() + " has order() of REPLACE_PARENT (" + Child.REPLACE_PARENT + ") but no parent element with name " + elementName + " could be found on type "
- + next.getDeclaringClass().getSimpleName());
+ throw new ConfigurationException("Field " + next.getName() + "' on target type " + theClass.getSimpleName() + " has order() of REPLACE_PARENT (" + Child.REPLACE_PARENT
+ + ") but no parent element with name " + elementName + " could be found on type " + next.getDeclaringClass().getSimpleName());
}
}
@@ -504,8 +455,7 @@ class ModelScanner {
// int max = childAnnotation.max();
/*
- * Anything that's marked as unknown is given a new ID that is <0 so that it doesn't conflict with any given
- * IDs and can be figured out later
+ * Anything that's marked as unknown is given a new ID that is <0 so that it doesn't conflict with any given IDs and can be figured out later
*/
if (order == Child.ORDER_UNKNOWN) {
order = Integer.MIN_VALUE;
@@ -572,7 +522,8 @@ class ModelScanner {
binder = getBoundCodeBinder(next);
}
- RuntimeChildDeclaredExtensionDefinition def = new RuntimeChildDeclaredExtensionDefinition(next, childAnnotation, descriptionAnnotation, extensionAttr, elementName, extensionAttr.url(), et, binder);
+ RuntimeChildDeclaredExtensionDefinition def = new RuntimeChildDeclaredExtensionDefinition(next, childAnnotation, descriptionAnnotation, extensionAttr, elementName, extensionAttr.url(), et,
+ binder);
if (IBaseEnumeration.class.isAssignableFrom(nextElementType)) {
def.setEnumerationType(ReflectionUtil.getGenericCollectionTypeOfFieldWithSecondOrderForList(next));
@@ -600,10 +551,10 @@ class ModelScanner {
RuntimeChildResourceDefinition def = new RuntimeChildResourceDefinition(next, elementName, childAnnotation, descriptionAnnotation, refTypesList);
orderMap.put(order, def);
- } else if (IResourceBlock.class.isAssignableFrom(nextElementType) || IBaseBackboneElement.class.isAssignableFrom(nextElementType) || IBaseDatatypeElement.class.isAssignableFrom(nextElementType)) {
+ } else if (IResourceBlock.class.isAssignableFrom(nextElementType) || IBaseBackboneElement.class.isAssignableFrom(nextElementType)
+ || IBaseDatatypeElement.class.isAssignableFrom(nextElementType)) {
/*
- * Child is a resource block (i.e. a sub-tag within a resource) TODO: do these have a better name
- * according to HL7?
+ * Child is a resource block (i.e. a sub-tag within a resource) TODO: do these have a better name according to HL7?
*/
Class extends IBase> blockDef = (Class extends IBase>) nextElementType;
@@ -611,13 +562,14 @@ class ModelScanner {
RuntimeChildResourceBlockDefinition def = new RuntimeChildResourceBlockDefinition(next, childAnnotation, descriptionAnnotation, elementName, blockDef);
orderMap.put(order, def);
- } else if (IDatatype.class.equals(nextElementType) || IElement.class.equals(nextElementType) || "Type".equals(nextElementType.getSimpleName()) || IBaseDatatype.class.equals(nextElementType)) {
+ } else if (IDatatype.class.equals(nextElementType) || IElement.class.equals(nextElementType) || "Type".equals(nextElementType.getSimpleName())
+ || IBaseDatatype.class.equals(nextElementType)) {
RuntimeChildAny def = new RuntimeChildAny(next, elementName, childAnnotation, descriptionAnnotation);
orderMap.put(order, def);
- } else if (IDatatype.class.isAssignableFrom(nextElementType) || IPrimitiveType.class.isAssignableFrom(nextElementType) || ICompositeType.class.isAssignableFrom(nextElementType) || IBaseDatatype.class.isAssignableFrom(nextElementType)
- || IBaseExtension.class.isAssignableFrom(nextElementType)) {
+ } else if (IDatatype.class.isAssignableFrom(nextElementType) || IPrimitiveType.class.isAssignableFrom(nextElementType) || ICompositeType.class.isAssignableFrom(nextElementType)
+ || IBaseDatatype.class.isAssignableFrom(nextElementType) || IBaseExtension.class.isAssignableFrom(nextElementType)) {
Class extends IBase> nextDatatype = (Class extends IBase>) nextElementType;
addScanAlso(nextDatatype);
@@ -645,10 +597,11 @@ class ModelScanner {
}
}
- CodeableConceptElement concept = pullAnnotation(theClass, next, CodeableConceptElement.class);
+ CodeableConceptElement concept = pullAnnotation(next, CodeableConceptElement.class);
if (concept != null) {
if (!ICodedDatatype.class.isAssignableFrom(nextDatatype)) {
- throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is marked as @" + CodeableConceptElement.class.getCanonicalName() + " but type is not a subtype of " + ICodedDatatype.class.getName());
+ throw new ConfigurationException("Field '" + elementName + "' in type '" + theClass.getCanonicalName() + "' is marked as @" + CodeableConceptElement.class.getCanonicalName()
+ + " but type is not a subtype of " + ICodedDatatype.class.getName());
} else {
Class extends ICodeEnum> type = concept.type();
myScanAlsoCodeTable.add(type);
@@ -711,21 +664,23 @@ class ModelScanner {
Class> parent = theClass.getSuperclass();
primaryNameProvider = false;
while (parent.equals(Object.class) == false && isBlank(resourceName)) {
- ResourceDef nextDef = pullAnnotation(theClass, parent, ResourceDef.class);
+ ResourceDef nextDef = pullAnnotation(parent, ResourceDef.class);
if (nextDef != null) {
resourceName = nextDef.name();
}
parent = parent.getSuperclass();
}
if (isBlank(resourceName)) {
- throw new ConfigurationException("Resource type @" + ResourceDef.class.getSimpleName() + " annotation contains no resource name(): " + theClass.getCanonicalName() + " - This is only allowed for types that extend other resource types ");
+ throw new ConfigurationException("Resource type @" + ResourceDef.class.getSimpleName() + " annotation contains no resource name(): " + theClass.getCanonicalName()
+ + " - This is only allowed for types that extend other resource types ");
}
}
String resourceId = resourceDefinition.id();
if (!isBlank(resourceId)) {
if (myIdToResourceDefinition.containsKey(resourceId)) {
- throw new ConfigurationException("The following resource types have the same ID of '" + resourceId + "' - " + theClass.getCanonicalName() + " and " + myIdToResourceDefinition.get(resourceId).getImplementingClass().getCanonicalName());
+ throw new ConfigurationException("The following resource types have the same ID of '" + resourceId + "' - " + theClass.getCanonicalName() + " and "
+ + myIdToResourceDefinition.get(resourceId).getImplementingClass().getCanonicalName());
}
}
@@ -751,7 +706,7 @@ class ModelScanner {
Map compositeFields = new LinkedHashMap();
for (Field nextField : theClass.getFields()) {
- SearchParamDefinition searchParam = pullAnnotation(theClass, nextField, SearchParamDefinition.class);
+ SearchParamDefinition searchParam = pullAnnotation(nextField, SearchParamDefinition.class);
if (searchParam != null) {
RestSearchParameterTypeEnum paramType = RestSearchParameterTypeEnum.valueOf(searchParam.type().toUpperCase());
if (paramType == null) {
@@ -761,7 +716,17 @@ class ModelScanner {
compositeFields.put(nextField, searchParam);
continue;
}
- RuntimeSearchParam param = new RuntimeSearchParam(searchParam.name(), searchParam.description(), searchParam.path(), paramType);
+
+ Set providesMembershipInCompartments = null;
+ Compartments compartmentsAnnotation = pullAnnotation(nextField, Compartments.class);
+ if (compartmentsAnnotation != null) {
+ providesMembershipInCompartments = new HashSet();
+ for (Compartment next : compartmentsAnnotation.providesMembershipIn()) {
+ providesMembershipInCompartments.add(next.name());
+ }
+ }
+
+ RuntimeSearchParam param = new RuntimeSearchParam(searchParam.name(), searchParam.description(), searchParam.path(), paramType, providesMembershipInCompartments);
theResourceDef.addSearchParam(param);
nameToParam.put(param.getName(), param);
}
@@ -774,13 +739,14 @@ class ModelScanner {
for (String nextName : searchParam.compositeOf()) {
RuntimeSearchParam param = nameToParam.get(nextName);
if (param == null) {
- ourLog.warn("Search parameter {}.{} declares that it is a composite with compositeOf value '{}' but that is not a valid parametr name itself. Valid values are: {}", new Object[] { theResourceDef.getName(), searchParam.name(), nextName, nameToParam.keySet() });
+ ourLog.warn("Search parameter {}.{} declares that it is a composite with compositeOf value '{}' but that is not a valid parametr name itself. Valid values are: {}",
+ new Object[] { theResourceDef.getName(), searchParam.name(), nextName, nameToParam.keySet() });
continue;
}
compositeOf.add(param);
}
- RuntimeSearchParam param = new RuntimeSearchParam(searchParam.name(), searchParam.description(), searchParam.path(), RestSearchParameterTypeEnum.COMPOSITE, compositeOf);
+ RuntimeSearchParam param = new RuntimeSearchParam(searchParam.name(), searchParam.description(), searchParam.path(), RestSearchParameterTypeEnum.COMPOSITE, compositeOf, null);
theResourceDef.addSearchParam(param);
}
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeSearchParam.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeSearchParam.java
index e7eb498daa8..c8ccc62ae68 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeSearchParam.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeSearchParam.java
@@ -3,6 +3,7 @@ package ca.uhn.fhir.context;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Set;
import java.util.StringTokenizer;
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
@@ -29,23 +30,30 @@ import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
public class RuntimeSearchParam {
+ private List myCompositeOf;
private String myDescription;
private String myName;
private RestSearchParameterTypeEnum myParamType;
private String myPath;
- private List myCompositeOf;
+ private Set myProvidesMembershipInCompartments;
- public RuntimeSearchParam(String theName, String theDescription, String thePath, RestSearchParameterTypeEnum theParamType) {
- this(theName, theDescription, thePath, theParamType, null);
- }
-
- public RuntimeSearchParam(String theName, String theDescription, String thePath, RestSearchParameterTypeEnum theParamType, List theCompositeOf) {
+ public RuntimeSearchParam(String theName, String theDescription, String thePath, RestSearchParameterTypeEnum theParamType, List theCompositeOf,
+ Set theProvidesMembershipInCompartments) {
super();
myName = theName;
myDescription = theDescription;
myPath = thePath;
myParamType = theParamType;
myCompositeOf = theCompositeOf;
+ if (theProvidesMembershipInCompartments != null && !theProvidesMembershipInCompartments.isEmpty()) {
+ myProvidesMembershipInCompartments = Collections.unmodifiableSet(theProvidesMembershipInCompartments);
+ } else {
+ myProvidesMembershipInCompartments = null;
+ }
+ }
+
+ public RuntimeSearchParam(String theName, String theDescription, String thePath, RestSearchParameterTypeEnum theParamType, Set theProvidesMembershipInCompartments) {
+ this(theName, theDescription, thePath, theParamType, null, theProvidesMembershipInCompartments);
}
public List getCompositeOf() {
@@ -70,10 +78,10 @@ public class RuntimeSearchParam {
public List getPathsSplit() {
String path = getPath();
- if (path.indexOf('|')==-1) {
+ if (path.indexOf('|') == -1) {
return Collections.singletonList(path);
}
-
+
List retVal = new ArrayList();
StringTokenizer tok = new StringTokenizer(path, "|");
while (tok.hasMoreElements()) {
@@ -83,4 +91,11 @@ public class RuntimeSearchParam {
return retVal;
}
+ /**
+ * Can return null
+ */
+ public Set getProvidesMembershipInCompartments() {
+ return myProvidesMembershipInCompartments;
+ }
+
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/annotation/Compartment.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/annotation/Compartment.java
new file mode 100644
index 00000000000..3a8df120949
--- /dev/null
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/annotation/Compartment.java
@@ -0,0 +1,19 @@
+package ca.uhn.fhir.model.api.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value= {})
+public @interface Compartment {
+
+ /**
+ * This may only be populated on a reference field. On such a field, places the containing
+ * resource in a compartment with the name(s) specified by the given strings, where the compartment
+ * belongs to the target resource. For example, this field could be populated with Patient
on
+ * the Observation.subject
field.
+ */
+ String name();
+
+}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/annotation/Compartments.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/annotation/Compartments.java
new file mode 100644
index 00000000000..826b6f95321
--- /dev/null
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/annotation/Compartments.java
@@ -0,0 +1,14 @@
+package ca.uhn.fhir.model.api.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value= {ElementType.FIELD})
+public @interface Compartments {
+
+ Compartment[] providesMembershipIn();
+
+}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/annotation/ResourceParam.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/annotation/ResourceParam.java
index 4ff18a50392..68b4f0d82b9 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/annotation/ResourceParam.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/annotation/ResourceParam.java
@@ -25,6 +25,29 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import ca.uhn.fhir.rest.server.IResourceProvider;
+
+/**
+ * Denotes a parameter for a REST method which will contain the resource actually
+ * being created/updated/etc in an operation which contains a resource in the HTTP request.
+ *
+ * For example, in a {@link Create} operation the method parameter annotated with this
+ * annotation will contain the actual resource being created.
+ *
+ *
+ * Parameters with this annotation should typically be of the type of resource being
+ * operated on (see below for an exception when raw data is required). For example, in a
+ * {@link IResourceProvider} for Patient resources, the parameter annotated with this
+ * annotation should be of type Patient.
+ *
+ *
+ * Note that in servers it is also acceptable to have parameters with this annotation
+ * which are of type {@link String} or of type byte[]
. Parameters of
+ * these types will contain the raw/unparsed HTTP request body. It is fine to
+ * have multiple parameters with this annotation, so you can have one parameter
+ * which accepts the parsed resource, and another which accepts the raw request.
+ *
+ */
@Target(value=ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface ResourceParam {
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseHttpClientInvocationWithContents.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseHttpClientInvocationWithContents.java
index 5159290b935..02469a665dc 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseHttpClientInvocationWithContents.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseHttpClientInvocationWithContents.java
@@ -1,5 +1,8 @@
package ca.uhn.fhir.rest.method;
+import static org.apache.commons.lang3.StringUtils.isBlank;
+import static org.apache.commons.lang3.StringUtils.isNotBlank;
+
/*
* #%L
* HAPI FHIR - Core Library
@@ -46,6 +49,7 @@ import ca.uhn.fhir.rest.server.IVersionSpecificBundleFactory;
* @author Doug Martin (Regenstrief Center for Biomedical Informatics)
*/
abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvocation {
+ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHttpClientInvocationWithContents.class);
private final Bundle myBundle;
private final BundleTypeEnum myBundleType;
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBindingWithResourceParam.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBindingWithResourceParam.java
index 0b65f425d7f..4977e93263a 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBindingWithResourceParam.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBindingWithResourceParam.java
@@ -117,7 +117,7 @@ abstract class BaseOutcomeReturningMethodBindingWithResourceParam extends BaseOu
@Override
public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
- IResource resource = (IResource) theArgs[myResourceParameterIndex];
+ IResource resource = (IResource) theArgs[myResourceParameterIndex]; // TODO: use IBaseResource
if (resource == null) {
throw new NullPointerException("Resource can not be null");
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/MethodUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/MethodUtil.java
index 8b774627289..5dfc7fa9b0e 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/MethodUtil.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/MethodUtil.java
@@ -451,10 +451,20 @@ public class MethodUtil {
mode = Mode.RESOURCE;
} else if (String.class.equals(parameterType)) {
mode = ResourceParameter.Mode.BODY;
+ } else if (byte[].class.equals(parameterType)) {
+ mode = ResourceParameter.Mode.BODY_BYTE_ARRAY;
} else if (EncodingEnum.class.equals(parameterType)) {
mode = Mode.ENCODING;
} else {
- throw new ConfigurationException("Method '" + theMethod.getName() + "' is annotated with @" + ResourceParam.class.getSimpleName() + " but has a type that is not an implemtation of " + IResource.class.getCanonicalName());
+ StringBuilder b = new StringBuilder();
+ b.append("Method '");
+ b.append(theMethod.getName());
+ b.append("' is annotated with @");
+ b.append(ResourceParam.class.getSimpleName());
+ b.append(" but has a type that is not an implemtation of ");
+ b.append(IBaseResource.class.getCanonicalName());
+ b.append(" or String or byte[]");
+ throw new ConfigurationException(b.toString());
}
param = new ResourceParameter((Class extends IResource>) parameterType, theProvider, mode);
} else if (nextAnnotation instanceof IdParam || nextAnnotation instanceof VersionIdParam) {
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ResourceParameter.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ResourceParameter.java
index 9650e3916a3..b9295c7da69 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ResourceParameter.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ResourceParameter.java
@@ -105,8 +105,10 @@ public class ResourceParameter implements IParameter {
return IOUtils.toString(createRequestReader(theRequest));
} catch (IOException e) {
// Shouldn't happen since we're reading from a byte array
- throw new InternalErrorException("Failed to load request");
+ throw new InternalErrorException("Failed to load request", e);
}
+ case BODY_BYTE_ARRAY:
+ return theRequest.loadRequestContents();
case ENCODING:
return RestfulServerUtils.determineRequestEncoding(theRequest);
case RESOURCE:
@@ -201,23 +203,27 @@ public class ResourceParameter implements IParameter {
}
public static IBaseResource parseResourceFromRequest(RequestDetails theRequest, BaseMethodBinding> theMethodBinding, Class extends IBaseResource> theResourceType) {
- IBaseResource retVal;
+ IBaseResource retVal = null;
+
if (IBaseBinary.class.isAssignableFrom(theResourceType)) {
- FhirContext ctx = theRequest.getServer().getFhirContext();
String ct = theRequest.getHeader(Constants.HEADER_CONTENT_TYPE);
+ if (EncodingEnum.forContentTypeStrict(ct) == null) {
+ FhirContext ctx = theRequest.getServer().getFhirContext();
IBaseBinary binary = (IBaseBinary) ctx.getResourceDefinition("Binary").newInstance();
binary.setContentType(ct);
binary.setContent(theRequest.loadRequestContents());
-
retVal = binary;
- } else {
+ }
+ }
+
+ if (retVal == null) {
retVal = loadResourceFromRequest(theRequest, theMethodBinding, theResourceType);
}
return retVal;
}
public enum Mode {
- BODY, ENCODING, RESOURCE
+ BODY, BODY_BYTE_ARRAY, ENCODING, RESOURCE
}
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/Constants.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/Constants.java
index 2a854e62764..cfa1bc0ca69 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/Constants.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/Constants.java
@@ -54,7 +54,7 @@ public class Constants {
public static final String FORMAT_XML = "xml";
public static final String HEADER_ACCEPT = "Accept";
public static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";
- public static final String HEADER_ACCEPT_VALUE_ALL = CT_FHIR_XML + ";q=1.0, " + CT_FHIR_JSON + ";q=1.0";
+ public static final String HEADER_ACCEPT_VALUE_XML_OR_JSON = CT_FHIR_XML + ";q=1.0, " + CT_FHIR_JSON + ";q=1.0";
public static final String HEADER_ALLOW = "Allow";
public static final String HEADER_AUTHORIZATION = "Authorization";
public static final String HEADER_AUTHORIZATION_VALPREFIX_BASIC = "Basic ";
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/EncodingEnum.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/EncodingEnum.java
index ceaae5bc886..29ddc0cf1c4 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/EncodingEnum.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/EncodingEnum.java
@@ -44,6 +44,7 @@ public enum EncodingEnum {
;
private static HashMap ourContentTypeToEncoding;
+ private static HashMap ourContentTypeToEncodingStrict;
static {
ourContentTypeToEncoding = new HashMap();
@@ -51,6 +52,9 @@ public enum EncodingEnum {
ourContentTypeToEncoding.put(next.getBundleContentType(), next);
ourContentTypeToEncoding.put(next.getResourceContentType(), next);
}
+
+ // Add before we add the lenient ones
+ ourContentTypeToEncodingStrict = new HashMap(ourContentTypeToEncoding);
/*
* These are wrong, but we add them just to be tolerant of other
@@ -88,10 +92,30 @@ public enum EncodingEnum {
return myResourceContentType;
}
+ /**
+ * Returns the encoding for a given content type, or null
if no encoding
+ * is found.
+ *
+ * This method is lenient! Things like "application/xml" will return {@link EncodingEnum#XML}
+ * even if the "+fhir" part is missing from the expected content type.
+ *
+ */
public static EncodingEnum forContentType(String theContentType) {
return ourContentTypeToEncoding.get(theContentType);
}
+ /**
+ * Returns the encoding for a given content type, or null
if no encoding
+ * is found.
+ *
+ * This method is NOT lenient! Things like "application/xml" will return null
+ *
+ * @see #forContentType(String)
+ */
+ public static EncodingEnum forContentTypeStrict(String theContentType) {
+ return ourContentTypeToEncodingStrict.get(theContentType);
+ }
+
public String getFormatContentType() {
return myFormatContentType;
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java
index 0f4b409cf23..be0f9944315 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java
@@ -517,7 +517,6 @@ public class RestfulServer extends HttpServlet implements IRestfulServer 0 && (nextString.charAt(0) == '_' || nextString.charAt(0) == '$' || nextString.equals(Constants.URL_TOKEN_METADATA));
}
- public static boolean requestIsBrowser(HttpServletRequest theRequest) {
- String userAgent = theRequest.getHeader("User-Agent");
- return userAgent != null && userAgent.contains("Mozilla");
- }
-
}
diff --git a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties
index fcde6e42738..6b7e5e1d9f5 100644
--- a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties
+++ b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties
@@ -43,6 +43,9 @@ ca.uhn.fhir.validation.ValidationResult.noIssuesDetected=No issues detected duri
# JPA Messages
ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.incomingNoopInTransaction=Transaction contains resource with operation NOOP. This is only valid as a response operation, not in a request.
+ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.invalidMatchUrlInvalidResourceType=Invalid match URL "{0}" - Unknown resource type: "{1}"
+ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.invalidMatchUrlNoMatches=Invalid match URL "{0}" - No resources match this search
+ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.invalidMatchUrlMultipleMatches=Invalid match URL "{0}" - Multiple resources match this search
ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.transactionOperationWithMultipleMatchFailure=Failed to {0} resource with match URL "{1}" because this search matched {2} resources
ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.transactionOperationFailedNoId=Failed to {0} resource in transaction because no ID was provided
ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.transactionOperationFailedUnknownId=Failed to {0} resource in transaction because no resource could be found with ID {1}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java
index e4aaff0ccd1..9285b207d59 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java
@@ -82,6 +82,7 @@ import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.RuntimeChildResourceDefinition;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
+import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
import ca.uhn.fhir.jpa.dao.dstu3.SearchParamExtractorDstu3;
import ca.uhn.fhir.jpa.entity.BaseHasResource;
import ca.uhn.fhir.jpa.entity.BaseResourceIndexedSearchParam;
@@ -147,19 +148,27 @@ import ca.uhn.fhir.util.OperationOutcomeUtil;
public abstract class BaseHapiFhirDao implements IDao {
+ public static final long INDEX_STATUS_INDEXED = Long.valueOf(1L);
+ public static final long INDEX_STATUS_INDEXING_FAILED = Long.valueOf(2L);
+ 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_INFO = "information";
+
public static final String OO_SEVERITY_WARN = "warning";
- /**
- * These are parameters which are supported by {@link BaseHapiFhirResourceDao#searchForIds(Map)}
- */
- static final Map> RESOURCE_META_PARAMS;
+ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiFhirDao.class);
+ private static final Map ourRetrievalContexts = new HashMap();
/**
* These are parameters which are supported by {@link BaseHapiFhirResourceDao#searchForIds(Map)}
*/
static final Map>> RESOURCE_META_AND_PARAMS;
+ /**
+ * These are parameters which are supported by {@link BaseHapiFhirResourceDao#searchForIds(Map)}
+ */
+ static final Map> RESOURCE_META_PARAMS;
+ public static final String UCUM_NS = "http://unitsofmeasure.org";
static {
Map> resourceMetaParams = new HashMap>();
Map>> resourceMetaAndParams = new HashMap>>();
@@ -177,14 +186,6 @@ public abstract class BaseHapiFhirDao implements IDao {
RESOURCE_META_AND_PARAMS = Collections.unmodifiableMap(resourceMetaAndParams);
}
- public static final long INDEX_STATUS_INDEXED = Long.valueOf(1L);
- public static final long INDEX_STATUS_INDEXING_FAILED = Long.valueOf(2L);
- public static final String NS_JPA_PROFILE = "https://github.com/jamesagnew/hapi-fhir/ns/jpa/profile";
- private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiFhirDao.class);
-
- private static final Map ourRetrievalContexts = new HashMap();
- public static final String UCUM_NS = "http://unitsofmeasure.org";
-
@Autowired(required = true)
private DaoConfig myConfig;
@@ -194,6 +195,9 @@ public abstract class BaseHapiFhirDao implements IDao {
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
protected EntityManager myEntityManager;
+ @Autowired
+ private IForcedIdDao myForcedIdDao;
+
@Autowired
private PlatformTransactionManager myPlatformTransactionManager;
@@ -222,23 +226,6 @@ public abstract class BaseHapiFhirDao implements IDao {
return InstantDt.withCurrentTime();
}
- public void setConfig(DaoConfig theConfig) {
- myConfig = theConfig;
- }
-
- public void setEntityManager(EntityManager theEntityManager) {
- myEntityManager = theEntityManager;
- }
-
- public void setPlatformTransactionManager(PlatformTransactionManager thePlatformTransactionManager) {
- myPlatformTransactionManager = thePlatformTransactionManager;
- }
-
- // @Override
- // public void setResourceDaos(List> theResourceDaos) {
- // myResourceDaos = theResourceDaos;
- // }
-
protected Set extractResourceLinks(ResourceTable theEntity, IBaseResource theResource) {
Set retVal = new HashSet();
@@ -377,6 +364,15 @@ public abstract class BaseHapiFhirDao implements IDao {
return retVal;
}
+ protected Set extractSearchParamCoords(ResourceTable theEntity, IBaseResource theResource) {
+ return mySearchParamExtractor.extractSearchParamCoords(theEntity, theResource);
+ }
+
+ // @Override
+ // public void setResourceDaos(List> theResourceDaos) {
+ // myResourceDaos = theResourceDaos;
+ // }
+
protected Set extractSearchParamDates(ResourceTable theEntity, IBaseResource theResource) {
return mySearchParamExtractor.extractSearchParamDates(theEntity, theResource);
}
@@ -385,14 +381,6 @@ public abstract class BaseHapiFhirDao implements IDao {
return mySearchParamExtractor.extractSearchParamNumber(theEntity, theResource);
}
- protected Set extractSearchParamUri(ResourceTable theEntity, IBaseResource theResource) {
- return mySearchParamExtractor.extractSearchParamUri(theEntity, theResource);
- }
-
- protected Set extractSearchParamCoords(ResourceTable theEntity, IBaseResource theResource) {
- return mySearchParamExtractor.extractSearchParamCoords(theEntity, theResource);
- }
-
protected Set extractSearchParamQuantity(ResourceTable theEntity, IBaseResource theResource) {
return mySearchParamExtractor.extractSearchParamQuantity(theEntity, theResource);
}
@@ -405,6 +393,74 @@ public abstract class BaseHapiFhirDao implements IDao {
return mySearchParamExtractor.extractSearchParamTokens(theEntity, theResource);
}
+ protected Set extractSearchParamUri(ResourceTable theEntity, IBaseResource theResource) {
+ return mySearchParamExtractor.extractSearchParamUri(theEntity, theResource);
+ }
+
+ private void extractTagsHapi(IResource theResource, ResourceTable theEntity, Set allDefs) {
+ TagList tagList = ResourceMetadataKeyEnum.TAG_LIST.get(theResource);
+ if (tagList != null) {
+ for (Tag next : tagList) {
+ TagDefinition tag = getTag(TagTypeEnum.TAG, next.getScheme(), next.getTerm(), next.getLabel());
+ allDefs.add(tag);
+ theEntity.addTag(tag);
+ theEntity.setHasTags(true);
+ }
+ }
+
+ List securityLabels = ResourceMetadataKeyEnum.SECURITY_LABELS.get(theResource);
+ if (securityLabels != null) {
+ for (BaseCodingDt next : securityLabels) {
+ TagDefinition tag = getTag(TagTypeEnum.SECURITY_LABEL, next.getSystemElement().getValue(), next.getCodeElement().getValue(), next.getDisplayElement().getValue());
+ allDefs.add(tag);
+ theEntity.addTag(tag);
+ theEntity.setHasTags(true);
+ }
+ }
+
+ List profiles = ResourceMetadataKeyEnum.PROFILES.get(theResource);
+ if (profiles != null) {
+ for (IIdType next : profiles) {
+ TagDefinition tag = getTag(TagTypeEnum.PROFILE, NS_JPA_PROFILE, next.getValue(), null);
+ allDefs.add(tag);
+ theEntity.addTag(tag);
+ theEntity.setHasTags(true);
+ }
+ }
+ }
+
+ private void extractTagsRi(IAnyResource theResource, ResourceTable theEntity, Set allDefs) {
+ List extends IBaseCoding> tagList = theResource.getMeta().getTag();
+ if (tagList != null) {
+ for (IBaseCoding next : tagList) {
+ TagDefinition tag = getTag(TagTypeEnum.TAG, next.getSystem(), next.getCode(), next.getDisplay());
+ allDefs.add(tag);
+ theEntity.addTag(tag);
+ theEntity.setHasTags(true);
+ }
+ }
+
+ List extends IBaseCoding> securityLabels = theResource.getMeta().getSecurity();
+ if (securityLabels != null) {
+ for (IBaseCoding next : securityLabels) {
+ TagDefinition tag = getTag(TagTypeEnum.SECURITY_LABEL, next.getSystem(), next.getCode(), next.getDisplay());
+ allDefs.add(tag);
+ theEntity.addTag(tag);
+ theEntity.setHasTags(true);
+ }
+ }
+
+ List extends IPrimitiveType> profiles = theResource.getMeta().getProfile();
+ if (profiles != null) {
+ for (IPrimitiveType next : profiles) {
+ TagDefinition tag = getTag(TagTypeEnum.PROFILE, NS_JPA_PROFILE, next.getValue(), null);
+ allDefs.add(tag);
+ theEntity.addTag(tag);
+ theEntity.setHasTags(true);
+ }
+ }
+ }
+
private List extractValues(String thePath, IBaseResource theResource) {
List values = new ArrayList();
FhirTerser t = getContext().newTerser();
@@ -441,21 +497,6 @@ public abstract class BaseHapiFhirDao implements IDao {
}
}
- protected void notifyInterceptors(RestOperationTypeEnum operationType, ActionRequestDetails requestDetails) {
- if (requestDetails.getId() != null && requestDetails.getId().hasResourceType() && isNotBlank(requestDetails.getResourceType())) {
- if (requestDetails.getId().getResourceType().equals(requestDetails.getResourceType()) == false) {
- throw new InternalErrorException("Inconsistent server state - Resource types don't match: " + requestDetails.getId().getResourceType() + " / " + requestDetails.getResourceType());
- }
- }
- List interceptors = getConfig().getInterceptors();
- if (interceptors == null) {
- return;
- }
- for (IServerInterceptor next : interceptors) {
- next.incomingRequestPreHandled(operationType, requestDetails);
- }
- }
-
protected DaoConfig getConfig() {
return myConfig;
}
@@ -595,7 +636,7 @@ public abstract class BaseHapiFhirDao implements IDao {
@Override
public List getResources(final int theFromIndex, final int theToIndex) {
- final StopWatch timer = new StopWatch();
+ final StopWatch grTimer = new StopWatch();
TransactionTemplate template = new TransactionTemplate(myPlatformTransactionManager);
return template.execute(new TransactionCallback>() {
@Override
@@ -604,10 +645,10 @@ public abstract class BaseHapiFhirDao implements IDao {
List tupleSubList = tuples.subList(theFromIndex, theToIndex);
searchHistoryCurrentVersion(tupleSubList, resEntities);
- ourLog.info("Loaded history from current versions in {} ms", timer.getMillisAndRestart());
+ ourLog.info("Loaded history from current versions in {} ms", grTimer.getMillisAndRestart());
searchHistoryHistory(tupleSubList, resEntities);
- ourLog.info("Loaded history from previous versions in {} ms", timer.getMillisAndRestart());
+ ourLog.info("Loaded history from previous versions in {} ms", grTimer.getMillisAndRestart());
Collections.sort(resEntities, new Comparator() {
@Override
@@ -616,9 +657,9 @@ public abstract class BaseHapiFhirDao implements IDao {
}
});
- int limit = theToIndex - theFromIndex;
- if (resEntities.size() > limit) {
- resEntities = resEntities.subList(0, limit);
+ int grLimit = theToIndex - theFromIndex;
+ if (resEntities.size() > grLimit) {
+ resEntities = resEntities.subList(0, grLimit);
}
ArrayList retVal = new ArrayList();
@@ -633,7 +674,7 @@ public abstract class BaseHapiFhirDao implements IDao {
}
throw e;
}
- IBaseResource resource = (IBaseResource) toResource(type.getImplementingClass(), next, true);
+ IBaseResource resource = toResource(type.getImplementingClass(), next, true);
retVal.add(resource);
}
return retVal;
@@ -642,29 +683,55 @@ public abstract class BaseHapiFhirDao implements IDao {
}
@Override
- public int size() {
- return tuples.size();
+ public Integer preferredPageSize() {
+ return null;
}
@Override
- public Integer preferredPageSize() {
- return null;
+ public int size() {
+ return tuples.size();
}
};
}
- protected static boolean isValidPid(IIdType theId) {
- if (theId == null || theId.getIdPart() == null) {
- return false;
- }
- String idPart = theId.getIdPart();
- for (int i = 0; i < idPart.length(); i++) {
- char nextChar = idPart.charAt(i);
- if (nextChar < '0' || nextChar > '9') {
- return false;
+ protected void notifyInterceptors(RestOperationTypeEnum operationType, ActionRequestDetails requestDetails) {
+ if (requestDetails.getId() != null && requestDetails.getId().hasResourceType() && isNotBlank(requestDetails.getResourceType())) {
+ if (requestDetails.getId().getResourceType().equals(requestDetails.getResourceType()) == false) {
+ throw new InternalErrorException("Inconsistent server state - Resource types don't match: " + requestDetails.getId().getResourceType() + " / " + requestDetails.getResourceType());
}
}
- return true;
+ List interceptors = getConfig().getInterceptors();
+ if (interceptors == null) {
+ return;
+ }
+ for (IServerInterceptor next : interceptors) {
+ next.incomingRequestPreHandled(operationType, requestDetails);
+ }
+ }
+
+ private String parseContentTextIntoWords(IBaseResource theResource) {
+ StringBuilder retVal = new StringBuilder();
+ @SuppressWarnings("rawtypes")
+ List childElements = getContext().newTerser().getAllPopulatedChildElementsOfType(theResource, IPrimitiveType.class);
+ for (@SuppressWarnings("rawtypes")
+ IPrimitiveType nextType : childElements) {
+ if (nextType instanceof StringDt || nextType.getClass().equals(StringType.class)) {
+ String nextValue = nextType.getValueAsString();
+ if (isNotBlank(nextValue)) {
+ retVal.append(nextValue.replace("\n", " ").replace("\r", " "));
+ retVal.append("\n");
+ }
+ }
+ }
+ return retVal.toString();
+ }
+
+ private void populateResourceId(final IBaseResource theResource, BaseHasResource theEntity) {
+ IIdType id = theEntity.getIdDt();
+ if (getContext().getVersion().getVersion().isRi()) {
+ id = new IdType(id.getValue());
+ }
+ theResource.setId(id);
}
protected void populateResourceIntoEntity(IBaseResource theResource, ResourceTable theEntity) {
@@ -729,77 +796,140 @@ public abstract class BaseHapiFhirDao implements IDao {
}
- private void extractTagsHapi(IResource theResource, ResourceTable theEntity, Set allDefs) {
- TagList tagList = ResourceMetadataKeyEnum.TAG_LIST.get(theResource);
- if (tagList != null) {
- for (Tag next : tagList) {
- TagDefinition tag = getTag(TagTypeEnum.TAG, next.getScheme(), next.getTerm(), next.getLabel());
- allDefs.add(tag);
- theEntity.addTag(tag);
- theEntity.setHasTags(true);
+ @SuppressWarnings("unchecked")
+ private R populateResourceMetadataHapi(Class theResourceType, BaseHasResource theEntity, boolean theForHistoryOperation, IResource res) {
+ R retVal = (R) res;
+ if (theEntity.getDeleted() != null) {
+ res = (IResource) myContext.getResourceDefinition(theResourceType).newInstance();
+ retVal = (R) res;
+ ResourceMetadataKeyEnum.DELETED_AT.put(res, new InstantDt(theEntity.getDeleted()));
+ if (theForHistoryOperation) {
+ ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.put(res, BundleEntryTransactionMethodEnum.DELETE);
+ }
+ } else if (theForHistoryOperation) {
+ /*
+ * If the create and update times match, this was when the resource was created so we should mark it as a POST.
+ * Otherwise, it's a PUT.
+ */
+ Date published = theEntity.getPublished().getValue();
+ Date updated = theEntity.getUpdated().getValue();
+ if (published.equals(updated)) {
+ ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.put(res, BundleEntryTransactionMethodEnum.POST);
+ } else {
+ ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.put(res, BundleEntryTransactionMethodEnum.PUT);
}
}
- List securityLabels = ResourceMetadataKeyEnum.SECURITY_LABELS.get(theResource);
- if (securityLabels != null) {
- for (BaseCodingDt next : securityLabels) {
- TagDefinition tag = getTag(TagTypeEnum.SECURITY_LABEL, next.getSystemElement().getValue(), next.getCodeElement().getValue(), next.getDisplayElement().getValue());
- allDefs.add(tag);
- theEntity.addTag(tag);
- theEntity.setHasTags(true);
- }
+ res.setId(theEntity.getIdDt());
+
+ ResourceMetadataKeyEnum.VERSION.put(res, Long.toString(theEntity.getVersion()));
+ ResourceMetadataKeyEnum.PUBLISHED.put(res, theEntity.getPublished());
+ ResourceMetadataKeyEnum.UPDATED.put(res, theEntity.getUpdated());
+ IDao.RESOURCE_PID.put(res, theEntity.getId());
+
+ if (theEntity.getTitle() != null) {
+ ResourceMetadataKeyEnum.TITLE.put(res, theEntity.getTitle());
}
- List profiles = ResourceMetadataKeyEnum.PROFILES.get(theResource);
- if (profiles != null) {
- for (IIdType next : profiles) {
- TagDefinition tag = getTag(TagTypeEnum.PROFILE, NS_JPA_PROFILE, next.getValue(), null);
- allDefs.add(tag);
- theEntity.addTag(tag);
- theEntity.setHasTags(true);
+ Collection extends BaseTag> tags = theEntity.getTags();
+ if (theEntity.isHasTags()) {
+ TagList tagList = new TagList();
+ List securityLabels = new ArrayList();
+ List profiles = new ArrayList();
+ for (BaseTag next : tags) {
+ switch (next.getTag().getTagType()) {
+ case PROFILE:
+ profiles.add(new IdDt(next.getTag().getCode()));
+ break;
+ case SECURITY_LABEL:
+ IBaseCoding secLabel = (IBaseCoding) myContext.getVersion().newCodingDt();
+ secLabel.setSystem(next.getTag().getSystem());
+ secLabel.setCode(next.getTag().getCode());
+ secLabel.setDisplay(next.getTag().getDisplay());
+ securityLabels.add(secLabel);
+ break;
+ case TAG:
+ tagList.add(new Tag(next.getTag().getSystem(), next.getTag().getCode(), next.getTag().getDisplay()));
+ break;
+ }
+ }
+ if (tagList.size() > 0) {
+ ResourceMetadataKeyEnum.TAG_LIST.put(res, tagList);
+ }
+ if (securityLabels.size() > 0) {
+ ResourceMetadataKeyEnum.SECURITY_LABELS.put(res, toBaseCodingList(securityLabels));
+ }
+ if (profiles.size() > 0) {
+ ResourceMetadataKeyEnum.PROFILES.put(res, profiles);
}
}
+
+ return retVal;
}
- private void extractTagsRi(IAnyResource theResource, ResourceTable theEntity, Set allDefs) {
- List extends IBaseCoding> tagList = theResource.getMeta().getTag();
- if (tagList != null) {
- for (IBaseCoding next : tagList) {
- TagDefinition tag = getTag(TagTypeEnum.TAG, next.getSystem(), next.getCode(), next.getDisplay());
- allDefs.add(tag);
- theEntity.addTag(tag);
- theEntity.setHasTags(true);
+ @SuppressWarnings("unchecked")
+ private R populateResourceMetadataRi(Class theResourceType, BaseHasResource theEntity, boolean theForHistoryOperation, IAnyResource res) {
+ R retVal = (R) res;
+ if (theEntity.getDeleted() != null) {
+ res = (IAnyResource) myContext.getResourceDefinition(theResourceType).newInstance();
+ retVal = (R) res;
+ ResourceMetadataKeyEnum.DELETED_AT.put(res, new InstantDt(theEntity.getDeleted()));
+ if (theForHistoryOperation) {
+ ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.put(res, HTTPVerb.DELETE.toCode());
+ }
+ } else if (theForHistoryOperation) {
+ /*
+ * If the create and update times match, this was when the resource was created so we should mark it as a POST.
+ * Otherwise, it's a PUT.
+ */
+ Date published = theEntity.getPublished().getValue();
+ Date updated = theEntity.getUpdated().getValue();
+ if (published.equals(updated)) {
+ ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.put(res, HTTPVerb.POST.toCode());
+ } else {
+ ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.put(res, HTTPVerb.PUT.toCode());
}
}
- List extends IBaseCoding> securityLabels = theResource.getMeta().getSecurity();
- if (securityLabels != null) {
- for (IBaseCoding next : securityLabels) {
- TagDefinition tag = getTag(TagTypeEnum.SECURITY_LABEL, next.getSystem(), next.getCode(), next.getDisplay());
- allDefs.add(tag);
- theEntity.addTag(tag);
- theEntity.setHasTags(true);
- }
- }
+ res.getMeta().getTag().clear();
+ res.getMeta().getProfile().clear();
+ res.getMeta().getSecurity().clear();
+ res.getMeta().setLastUpdated(null);
+ res.getMeta().setVersionId(null);
+
+ populateResourceId(res, theEntity);
- List extends IPrimitiveType> profiles = theResource.getMeta().getProfile();
- if (profiles != null) {
- for (IPrimitiveType next : profiles) {
- TagDefinition tag = getTag(TagTypeEnum.PROFILE, NS_JPA_PROFILE, next.getValue(), null);
- allDefs.add(tag);
- theEntity.addTag(tag);
- theEntity.setHasTags(true);
+ res.getMeta().setLastUpdated(theEntity.getUpdatedDate());
+ IDao.RESOURCE_PID.put(res, theEntity.getId());
+
+ Collection extends BaseTag> tags = theEntity.getTags();
+ if (theEntity.isHasTags()) {
+ for (BaseTag next : tags) {
+ switch (next.getTag().getTagType()) {
+ case PROFILE:
+ res.getMeta().addProfile(next.getTag().getCode());
+ break;
+ case SECURITY_LABEL:
+ IBaseCoding sec = res.getMeta().addSecurity();
+ sec.setSystem(next.getTag().getSystem());
+ sec.setCode(next.getTag().getCode());
+ sec.setDisplay(next.getTag().getDisplay());
+ break;
+ case TAG:
+ IBaseCoding tag = res.getMeta().addTag();
+ tag.setSystem(next.getTag().getSystem());
+ tag.setCode(next.getTag().getCode());
+ tag.setDisplay(next.getTag().getDisplay());
+ break;
+ }
}
}
+ return retVal;
}
/**
- * This method is called when an update to an existing resource detects that the resource supplied for update is
- * missing a tag/profile/security label that the currently persisted resource holds.
- *
- * The default implementation removes any profile declarations, but leaves tags and security labels in place.
- * Subclasses may choose to override and change this behaviour.
- *
+ * Subclasses may override to provide behaviour. Called when a resource has been inserved into the database for the
+ * first time.
*
* @param theEntity
* The entity being updated (Do not modify the entity! Undefined behaviour will occur!)
@@ -808,35 +938,22 @@ public abstract class BaseHapiFhirDao implements IDao {
* @return Returns true
if the tag should be removed
* @see Updates to Tags, Profiles, and Security Labels for a description of the logic that the default behaviour folows.
*/
- protected boolean shouldDroppedTagBeRemovedOnUpdate(ResourceTable theEntity, ResourceTag theTag) {
- if (theTag.getTag().getTagType() == TagTypeEnum.PROFILE) {
- return true;
- }
- return false;
+ @SuppressWarnings("unused")
+ protected void postPersist(ResourceTable theEntity, T theResource) {
+ // nothing
}
- @CoverageIgnore
- protected static IQueryParameterAnd> newInstanceAnd(String chain) {
- IQueryParameterAnd> type;
- Class extends IQueryParameterAnd>> clazz = RESOURCE_META_AND_PARAMS.get(chain);
- try {
- type = clazz.newInstance();
- } catch (Exception e) {
- throw new InternalErrorException("Failure creating instance of " + clazz, e);
- }
- return type;
- }
-
- @CoverageIgnore
- protected static IQueryParameterType newInstanceType(String chain) {
- IQueryParameterType type;
- Class extends IQueryParameterType> clazz = RESOURCE_META_PARAMS.get(chain);
- try {
- type = clazz.newInstance();
- } catch (Exception e) {
- throw new InternalErrorException("Failure creating instance of " + clazz, e);
- }
- return type;
+ /**
+ * Subclasses may override to provide behaviour. Called when a resource has been inserved into the database for the
+ * first time.
+ *
+ * @param theEntity
+ * The resource
+ * @param theResource
+ * The resource being persisted
+ */
+ protected void postUpdate(ResourceTable theEntity, T theResource) {
+ // nothing
}
protected Set processMatchUrl(String theMatchUrl, Class theResourceType) {
@@ -854,100 +971,10 @@ public abstract class BaseHapiFhirDao implements IDao {
return ids;
}
- public static SearchParameterMap translateMatchUrl(String theMatchUrl, RuntimeResourceDefinition resourceDef) {
- SearchParameterMap paramMap = new SearchParameterMap();
- List parameters = translateMatchUrl(theMatchUrl);
-
- ArrayListMultimap nameToParamLists = ArrayListMultimap.create();
- for (NameValuePair next : parameters) {
- if (isBlank(next.getValue())) {
- continue;
- }
-
- String paramName = next.getName();
- String qualifier = null;
- for (int i = 0; i < paramName.length(); i++) {
- switch (paramName.charAt(i)) {
- case '.':
- case ':':
- qualifier = paramName.substring(i);
- paramName = paramName.substring(0, i);
- i = Integer.MAX_VALUE - 1;
- break;
- }
- }
-
- QualifiedParamList paramList = QualifiedParamList.splitQueryStringByCommasIgnoreEscape(qualifier, next.getValue());
- nameToParamLists.put(paramName, paramList);
- }
-
- for (String nextParamName : nameToParamLists.keySet()) {
- List paramList = nameToParamLists.get(nextParamName);
- if (Constants.PARAM_LASTUPDATED.equals(nextParamName)) {
- if (paramList != null && paramList.size() > 0) {
- if (paramList.size() > 2) {
- throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - Can not have more than 2 " + Constants.PARAM_LASTUPDATED + " parameter repetitions");
- } else {
- DateRangeParam p1 = new DateRangeParam();
- p1.setValuesAsQueryTokens(paramList);
- paramMap.setLastUpdated(p1);
- }
- }
- continue;
- }
-
- if (Constants.PARAM_COUNT.equals(nextParamName)) {
- if (paramList.size() > 0 && paramList.get(0).size() > 0) {
- String intString = paramList.get(0).get(0);
- try {
- paramMap.setCount(Integer.parseInt(intString));
- } catch (NumberFormatException e) {
- throw new InvalidRequestException("Invalid " + Constants.PARAM_COUNT + " value: " + intString);
- }
- }
- continue;
- }
-
- if (RESOURCE_META_PARAMS.containsKey(nextParamName)) {
- if (isNotBlank(paramList.get(0).getQualifier()) && paramList.get(0).getQualifier().startsWith(".")) {
- throw new InvalidRequestException("Invalid parameter chain: " + nextParamName + paramList.get(0).getQualifier());
- }
- IQueryParameterAnd> type = newInstanceAnd(nextParamName);
- type.setValuesAsQueryTokens((paramList));
- paramMap.add(nextParamName, type);
- } else if (nextParamName.startsWith("_")) {
- // ignore these since they aren't search params (e.g. _sort)
- } else {
- RuntimeSearchParam paramDef = resourceDef.getSearchParam(nextParamName);
- if (paramDef == null) {
- throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - Resource type " + resourceDef.getName() + " does not have a parameter with name: " + nextParamName);
- }
-
- IQueryParameterAnd> param = MethodUtil.parseQueryParams(paramDef, nextParamName, paramList);
- paramMap.add(nextParamName, param);
- }
- }
- return paramMap;
- }
-
- protected static List translateMatchUrl(String theMatchUrl) {
- List parameters;
- String matchUrl = theMatchUrl;
- int questionMarkIndex = matchUrl.indexOf('?');
- if (questionMarkIndex != -1) {
- matchUrl = matchUrl.substring(questionMarkIndex + 1);
- }
- matchUrl = matchUrl.replace("|", "%7C");
- matchUrl = matchUrl.replace("=>=", "=%3E%3D");
- matchUrl = matchUrl.replace("=<=", "=%3C%3D");
- matchUrl = matchUrl.replace("=>", "=%3E");
- matchUrl = matchUrl.replace("=<", "=%3C");
- if (matchUrl.contains(" ")) {
- throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - URL is invalid (must not contain spaces)");
- }
-
- parameters = URLEncodedUtils.parse((matchUrl), Constants.CHARSET_UTF8, '&');
- return parameters;
+ @SuppressWarnings("unused")
+ @CoverageIgnore
+ public BaseHasResource readEntity(IIdType theValueId) {
+ throw new NotImplementedException("");
}
private void searchHistoryCurrentVersion(List theTuples, List theRetVal) {
@@ -1086,6 +1113,10 @@ public abstract class BaseHapiFhirDao implements IDao {
}
}
+ public void setConfig(DaoConfig theConfig) {
+ myConfig = theConfig;
+ }
+
// protected MetaDt toMetaDt(Collection tagDefinitions) {
// MetaDt retVal = new MetaDt();
// for (TagDefinition next : tagDefinitions) {
@@ -1122,6 +1153,37 @@ public abstract class BaseHapiFhirDao implements IDao {
}
}
+ public void setEntityManager(EntityManager theEntityManager) {
+ myEntityManager = theEntityManager;
+ }
+
+ public void setPlatformTransactionManager(PlatformTransactionManager thePlatformTransactionManager) {
+ myPlatformTransactionManager = thePlatformTransactionManager;
+ }
+
+ /**
+ * This method is called when an update to an existing resource detects that the resource supplied for update is
+ * missing a tag/profile/security label that the currently persisted resource holds.
+ *
+ * The default implementation removes any profile declarations, but leaves tags and security labels in place.
+ * Subclasses may choose to override and change this behaviour.
+ *
+ *
+ * @param theEntity
+ * The entity being updated (Do not modify the entity! Undefined behaviour will occur!)
+ * @param theTag
+ * The tag
+ * @return Retturns true
if the tag should be removed
+ * @see Updates to Tags, Profiles, and Security
+ * Labels for a description of the logic that the default behaviour folows.
+ */
+ protected boolean shouldDroppedTagBeRemovedOnUpdate(ResourceTable theEntity, ResourceTag theTag) {
+ if (theTag.getTag().getTagType() == TagTypeEnum.PROFILE) {
+ return true;
+ }
+ return false;
+ }
+
protected ResourceTable toEntity(IResource theResource) {
ResourceTable retVal = new ResourceTable();
@@ -1136,191 +1198,53 @@ public abstract class BaseHapiFhirDao implements IDao {
return toResource(type.getImplementingClass(), theEntity, theForHistoryOperation);
}
- @Override
- @SuppressWarnings("unchecked")
- public R toResource(Class theResourceType, BaseHasResource theEntity, boolean theForHistoryOperation) {
- String resourceText = null;
- switch (theEntity.getEncoding()) {
- case JSON:
+ @Override
+ public R toResource(Class theResourceType, BaseHasResource theEntity, boolean theForHistoryOperation) {
+ String resourceText = null;
+ switch (theEntity.getEncoding()) {
+ case JSON:
+ try {
+ resourceText = new String(theEntity.getResource(), "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new Error("Should not happen", e);
+ }
+ break;
+ case JSONC:
+ resourceText = GZipUtil.decompress(theEntity.getResource());
+ break;
+ }
+
+ IParser parser = theEntity.getEncoding().newParser(getContext(theEntity.getFhirVersion()));
+ R retVal;
try {
- resourceText = new String(theEntity.getResource(), "UTF-8");
- } catch (UnsupportedEncodingException e) {
- throw new Error("Should not happen", e);
+ retVal = parser.parseResource(theResourceType, resourceText);
+ } catch (Exception e) {
+ StringBuilder b = new StringBuilder();
+ b.append("Failed to parse database resource[");
+ b.append(theResourceType);
+ b.append("/");
+ b.append(theEntity.getIdDt().getIdPart());
+ b.append(" (pid ");
+ b.append(theEntity.getId());
+ b.append(", version ");
+ b.append(myContext.getVersion().getVersion());
+ b.append("): ");
+ b.append(e.getMessage());
+ String msg = b.toString();
+ ourLog.error(msg, e);
+ throw new DataFormatException(msg, e);
}
- break;
- case JSONC:
- resourceText = GZipUtil.decompress(theEntity.getResource());
- break;
- }
- IParser parser = theEntity.getEncoding().newParser(getContext(theEntity.getFhirVersion()));
- R retVal;
- try {
- retVal = parser.parseResource(theResourceType, resourceText);
- } catch (Exception e) {
- StringBuilder b = new StringBuilder();
- b.append("Failed to parse database resource[");
- b.append(theResourceType);
- b.append("/");
- b.append(theEntity.getIdDt().getIdPart());
- b.append(" (pid ");
- b.append(theEntity.getId());
- b.append(", version ");
- b.append(myContext.getVersion().getVersion());
- b.append("): ");
- b.append(e.getMessage());
- String msg = b.toString();
- ourLog.error(msg, e);
- throw new DataFormatException(msg, e);
- }
-
- if (retVal instanceof IResource) {
- IResource res = (IResource) retVal;
- retVal = populateResourceMetadataHapi(theResourceType, theEntity, theForHistoryOperation, res);
- } else {
- IAnyResource res = (IAnyResource) retVal;
- retVal = populateResourceMetadataRi(theResourceType, theEntity, theForHistoryOperation, res);
- }
- return retVal;
- }
-
- private R populateResourceMetadataHapi(Class theResourceType, BaseHasResource theEntity, boolean theForHistoryOperation, IResource res) {
- R retVal = (R) res;
- if (theEntity.getDeleted() != null) {
- res = (IResource) myContext.getResourceDefinition(theResourceType).newInstance();
- retVal = (R) res;
- ResourceMetadataKeyEnum.DELETED_AT.put(res, new InstantDt(theEntity.getDeleted()));
- if (theForHistoryOperation) {
- ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.put(res, BundleEntryTransactionMethodEnum.DELETE);
- }
- } else if (theForHistoryOperation) {
- /*
- * If the create and update times match, this was when the resource was created so we should mark it as a POST.
- * Otherwise, it's a PUT.
- */
- Date published = theEntity.getPublished().getValue();
- Date updated = theEntity.getUpdated().getValue();
- if (published.equals(updated)) {
- ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.put(res, BundleEntryTransactionMethodEnum.POST);
+ if (retVal instanceof IResource) {
+ IResource res = (IResource) retVal;
+ retVal = populateResourceMetadataHapi(theResourceType, theEntity, theForHistoryOperation, res);
} else {
- ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.put(res, BundleEntryTransactionMethodEnum.PUT);
+ IAnyResource res = (IAnyResource) retVal;
+ retVal = populateResourceMetadataRi(theResourceType, theEntity, theForHistoryOperation, res);
}
+ return retVal;
}
- res.setId(theEntity.getIdDt());
-
- ResourceMetadataKeyEnum.VERSION.put(res, Long.toString(theEntity.getVersion()));
- ResourceMetadataKeyEnum.PUBLISHED.put(res, theEntity.getPublished());
- ResourceMetadataKeyEnum.UPDATED.put(res, theEntity.getUpdated());
- IDao.RESOURCE_PID.put(res, theEntity.getId());
-
- if (theEntity.getTitle() != null) {
- ResourceMetadataKeyEnum.TITLE.put(res, theEntity.getTitle());
- }
-
- Collection extends BaseTag> tags = theEntity.getTags();
- if (theEntity.isHasTags()) {
- TagList tagList = new TagList();
- List securityLabels = new ArrayList();
- List profiles = new ArrayList();
- for (BaseTag next : tags) {
- switch (next.getTag().getTagType()) {
- case PROFILE:
- profiles.add(new IdDt(next.getTag().getCode()));
- break;
- case SECURITY_LABEL:
- IBaseCoding secLabel = (IBaseCoding) myContext.getVersion().newCodingDt();
- secLabel.setSystem(next.getTag().getSystem());
- secLabel.setCode(next.getTag().getCode());
- secLabel.setDisplay(next.getTag().getDisplay());
- securityLabels.add(secLabel);
- break;
- case TAG:
- tagList.add(new Tag(next.getTag().getSystem(), next.getTag().getCode(), next.getTag().getDisplay()));
- break;
- }
- }
- if (tagList.size() > 0) {
- ResourceMetadataKeyEnum.TAG_LIST.put(res, tagList);
- }
- if (securityLabels.size() > 0) {
- ResourceMetadataKeyEnum.SECURITY_LABELS.put(res, toBaseCodingList(securityLabels));
- }
- if (profiles.size() > 0) {
- ResourceMetadataKeyEnum.PROFILES.put(res, profiles);
- }
- }
-
- return retVal;
- }
-
- private R populateResourceMetadataRi(Class theResourceType, BaseHasResource theEntity, boolean theForHistoryOperation, IAnyResource res) {
- R retVal = (R) res;
- if (theEntity.getDeleted() != null) {
- res = (IAnyResource) myContext.getResourceDefinition(theResourceType).newInstance();
- retVal = (R) res;
- ResourceMetadataKeyEnum.DELETED_AT.put(res, new InstantDt(theEntity.getDeleted()));
- if (theForHistoryOperation) {
- ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.put(res, HTTPVerb.DELETE.toCode());
- }
- } else if (theForHistoryOperation) {
- /*
- * If the create and update times match, this was when the resource was created so we should mark it as a POST.
- * Otherwise, it's a PUT.
- */
- Date published = theEntity.getPublished().getValue();
- Date updated = theEntity.getUpdated().getValue();
- if (published.equals(updated)) {
- ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.put(res, HTTPVerb.POST.toCode());
- } else {
- ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.put(res, HTTPVerb.PUT.toCode());
- }
- }
-
- res.getMeta().getTag().clear();
- res.getMeta().getProfile().clear();
- res.getMeta().getSecurity().clear();
- res.getMeta().setLastUpdated(null);
- res.getMeta().setVersionId(null);
-
- populateResourceId(res, theEntity);
-
- res.getMeta().setLastUpdated(theEntity.getUpdatedDate());
- IDao.RESOURCE_PID.put(res, theEntity.getId());
-
- Collection extends BaseTag> tags = theEntity.getTags();
- if (theEntity.isHasTags()) {
- for (BaseTag next : tags) {
- switch (next.getTag().getTagType()) {
- case PROFILE:
- res.getMeta().addProfile(next.getTag().getCode());
- break;
- case SECURITY_LABEL:
- IBaseCoding sec = res.getMeta().addSecurity();
- sec.setSystem(next.getTag().getSystem());
- sec.setCode(next.getTag().getCode());
- sec.setDisplay(next.getTag().getDisplay());
- break;
- case TAG:
- IBaseCoding tag = res.getMeta().addTag();
- tag.setSystem(next.getTag().getSystem());
- tag.setCode(next.getTag().getCode());
- tag.setDisplay(next.getTag().getDisplay());
- break;
- }
- }
- }
- return retVal;
- }
-
- private static List toBaseCodingList(List theSecurityLabels) {
- ArrayList retVal = new ArrayList(theSecurityLabels.size());
- for (IBaseCoding next : theSecurityLabels) {
- retVal.add((BaseCodingDt) next);
- }
- return retVal;
- }
-
protected String toResourceName(Class extends IBaseResource> theResourceType) {
return myContext.getResourceDefinition(theResourceType).getName();
}
@@ -1333,28 +1257,8 @@ public abstract class BaseHapiFhirDao implements IDao {
return translateForcedIdToPid(theId, myEntityManager);
}
- public static void validateResourceType(BaseHasResource theEntity, String theResourceName) {
- if (!theResourceName.equals(theEntity.getResourceType())) {
- throw new ResourceNotFoundException("Resource with ID " + theEntity.getIdDt().getIdPart() + " exists but it is not of type " + theResourceName + ", found resource of type " + theEntity.getResourceType());
- }
- }
-
- static Long translateForcedIdToPid(IIdType theId, EntityManager entityManager) {
- if (isValidPid(theId)) {
- return theId.getIdPartAsLong();
- } else {
- TypedQuery q = entityManager.createNamedQuery("Q_GET_FORCED_ID", ForcedId.class);
- q.setParameter("ID", theId.getIdPart());
- try {
- return q.getSingleResult().getResourcePid();
- } catch (NoResultException e) {
- throw new ResourceNotFoundException(theId);
- }
- }
- }
-
protected String translatePidIdToForcedId(Long theId) {
- ForcedId forcedId = myEntityManager.find(ForcedId.class, theId);
+ ForcedId forcedId = myForcedIdDao.findByResourcePid(theId);
if (forcedId != null) {
return forcedId.getForcedId();
} else {
@@ -1477,6 +1381,49 @@ public abstract class BaseHapiFhirDao implements IDao {
}
}
+ /*
+ * Handle references within the resource that are match URLs, for example
+ * references like "Patient?identifier=foo". These match URLs are resolved
+ * and replaced with the ID of the matching resource.
+ */
+ if (myConfig.isAllowInlineMatchUrlReferences()) {
+ FhirTerser terser = getContext().newTerser();
+ List allRefs = terser.getAllPopulatedChildElementsOfType(theResource, IBaseReference.class);
+ for (IBaseReference nextRef : allRefs) {
+ IIdType nextId = nextRef.getReferenceElement();
+ String nextIdText = nextId.getValue();
+ int qmIndex = nextIdText.indexOf('?');
+ if (qmIndex != -1) {
+ for (int i = qmIndex - 1; i >= 0; i--) {
+ if (nextIdText.charAt(i) == '/') {
+ nextIdText = nextIdText.substring(i + 1);
+ break;
+ }
+ }
+ String resourceTypeString = nextIdText.substring(0, nextIdText.indexOf('?'));
+ RuntimeResourceDefinition matchResourceDef = getContext().getResourceDefinition(resourceTypeString);
+ if (matchResourceDef == null) {
+ String msg = getContext().getLocalizer().getMessage(BaseHapiFhirDao.class, "invalidMatchUrlInvalidResourceType", nextId.getValue(), resourceTypeString);
+ throw new InvalidRequestException(msg);
+ }
+ Class extends IBaseResource> matchResourceType = matchResourceDef.getImplementingClass();
+ Set matches = processMatchUrl(nextIdText, matchResourceType);
+ if (matches.isEmpty()) {
+ String msg = getContext().getLocalizer().getMessage(BaseHapiFhirDao.class, "invalidMatchUrlNoMatches", nextId.getValue());
+ throw new InvalidRequestException(msg);
+ }
+ if (matches.size() > 1) {
+ String msg = getContext().getLocalizer().getMessage(BaseHapiFhirDao.class, "invalidMatchUrlMultipleMatches", nextId.getValue());
+ throw new InvalidRequestException(msg);
+ }
+ Long next = matches.iterator().next();
+ String newId = resourceTypeString + '/' + translatePidIdToForcedId(next);
+ ourLog.info("Replacing inline match URL[{}] with ID[{}}", nextId.getValue(), newId);
+ nextRef.setReference(newId);
+ }
+ }
+ }
+
links = extractResourceLinks(theEntity, theResource);
/*
@@ -1620,40 +1567,21 @@ public abstract class BaseHapiFhirDao implements IDao {
return theEntity;
}
- private void populateResourceId(final IBaseResource theResource, BaseHasResource theEntity) {
- IIdType id = theEntity.getIdDt();
- if (getContext().getVersion().getVersion().isRi()) {
- id = new IdType(id.getValue());
+ protected void validateDeleteConflictsEmptyOrThrowException(List theDeleteConflicts) {
+ if (theDeleteConflicts.isEmpty()) {
+ return;
}
- theResource.setId(id);
- }
- /**
- * Subclasses may override to provide behaviour. Called when a resource has been inserved into the database for the
- * first time.
- *
- * @param theEntity
- * The resource
- * @param theResource
- * The resource being persisted
- */
- protected void postUpdate(ResourceTable theEntity, T theResource) {
- // nothing
- }
+ IBaseOperationOutcome oo = OperationOutcomeUtil.newInstance(getContext());
+ for (DeleteConflict next : theDeleteConflicts) {
+ String msg = "Unable to delete " + next.getTargetId().toUnqualifiedVersionless().getValue() + " because at least one resource has a reference to this resource. First reference found was resource " + next.getTargetId().toUnqualifiedVersionless().getValue() + " in path "
+ + next.getSourcePath();
+ OperationOutcomeUtil.addIssue(getContext(), oo, OO_SEVERITY_ERROR, msg, null, "processing");
+ }
- /**
- * Subclasses may override to provide behaviour. Called when a resource has been inserved into the database for the
- * first time.
- *
- * @param theEntity
- * The resource
- * @param theResource
- * The resource being persisted
- */
- protected void postPersist(ResourceTable theEntity, T theResource) {
- // nothing
+ throw new ResourceVersionConflictException("Delete failed because of constraint failure", oo);
}
-
+
/**
* This method is invoked immediately before storing a new resource, or an update to an existing resource to allow
* the DAO to ensure that it is valid for persistence. By default, checks for the "subsetted" tag and rejects
@@ -1683,6 +1611,44 @@ public abstract class BaseHapiFhirDao implements IDao {
}
}
+ protected static boolean isValidPid(IIdType theId) {
+ if (theId == null || theId.getIdPart() == null) {
+ return false;
+ }
+ String idPart = theId.getIdPart();
+ for (int i = 0; i < idPart.length(); i++) {
+ char nextChar = idPart.charAt(i);
+ if (nextChar < '0' || nextChar > '9') {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @CoverageIgnore
+ protected static IQueryParameterAnd> newInstanceAnd(String chain) {
+ IQueryParameterAnd> type;
+ Class extends IQueryParameterAnd>> clazz = RESOURCE_META_AND_PARAMS.get(chain);
+ try {
+ type = clazz.newInstance();
+ } catch (Exception e) {
+ throw new InternalErrorException("Failure creating instance of " + clazz, e);
+ }
+ return type;
+ }
+
+ @CoverageIgnore
+ protected static IQueryParameterType newInstanceType(String chain) {
+ IQueryParameterType type;
+ Class extends IQueryParameterType> clazz = RESOURCE_META_PARAMS.get(chain);
+ try {
+ type = clazz.newInstance();
+ } catch (Exception e) {
+ throw new InternalErrorException("Failure creating instance of " + clazz, e);
+ }
+ return type;
+ }
+
public static String normalizeString(String theString) {
char[] out = new char[theString.length()];
theString = Normalizer.normalize(theString, Normalizer.Form.NFD);
@@ -1732,40 +1698,128 @@ public abstract class BaseHapiFhirDao implements IDao {
return b.toString();
}
- private String parseContentTextIntoWords(IBaseResource theResource) {
- StringBuilder retVal = new StringBuilder();
- @SuppressWarnings("rawtypes")
- List childElements = getContext().newTerser().getAllPopulatedChildElementsOfType(theResource, IPrimitiveType.class);
- for (@SuppressWarnings("rawtypes")
- IPrimitiveType nextType : childElements) {
- if (nextType instanceof StringDt || nextType.getClass().equals(StringType.class)) {
- String nextValue = nextType.getValueAsString();
- if (isNotBlank(nextValue)) {
- retVal.append(nextValue.replace("\n", " ").replace("\r", " "));
- retVal.append("\n");
- }
+ private static List toBaseCodingList(List theSecurityLabels) {
+ ArrayList retVal = new ArrayList(theSecurityLabels.size());
+ for (IBaseCoding next : theSecurityLabels) {
+ retVal.add((BaseCodingDt) next);
+ }
+ return retVal;
+}
+
+ static Long translateForcedIdToPid(IIdType theId, EntityManager entityManager) {
+ if (isValidPid(theId)) {
+ return theId.getIdPartAsLong();
+ } else {
+ TypedQuery q = entityManager.createNamedQuery("Q_GET_FORCED_ID", ForcedId.class);
+ q.setParameter("ID", theId.getIdPart());
+ try {
+ return q.getSingleResult().getResourcePid();
+ } catch (NoResultException e) {
+ throw new ResourceNotFoundException(theId);
}
}
- return retVal.toString();
}
- protected void validateDeleteConflictsEmptyOrThrowException(List theDeleteConflicts) {
- if (theDeleteConflicts.isEmpty()) {
- return;
+ protected static List translateMatchUrl(String theMatchUrl) {
+ List parameters;
+ String matchUrl = theMatchUrl;
+ int questionMarkIndex = matchUrl.indexOf('?');
+ if (questionMarkIndex != -1) {
+ matchUrl = matchUrl.substring(questionMarkIndex + 1);
+ }
+ matchUrl = matchUrl.replace("|", "%7C");
+ matchUrl = matchUrl.replace("=>=", "=%3E%3D");
+ matchUrl = matchUrl.replace("=<=", "=%3C%3D");
+ matchUrl = matchUrl.replace("=>", "=%3E");
+ matchUrl = matchUrl.replace("=<", "=%3C");
+ if (matchUrl.contains(" ")) {
+ throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - URL is invalid (must not contain spaces)");
}
- IBaseOperationOutcome oo = OperationOutcomeUtil.newInstance(getContext());
- for (DeleteConflict next : theDeleteConflicts) {
- String msg = "Unable to delete " + next.getTargetId().toUnqualifiedVersionless().getValue() + " because at least one resource has a reference to this resource. First reference found was resource " + next.getTargetId().toUnqualifiedVersionless().getValue() + " in path "
- + next.getSourcePath();
- OperationOutcomeUtil.addIssue(getContext(), oo, OO_SEVERITY_ERROR, msg, null, "processing");
- }
-
- throw new ResourceVersionConflictException("Delete failed because of constraint failure", oo);
+ parameters = URLEncodedUtils.parse((matchUrl), Constants.CHARSET_UTF8, '&');
+ return parameters;
}
- public BaseHasResource readEntity(IIdType theValueId) {
- throw new NotImplementedException("");
+ public static SearchParameterMap translateMatchUrl(String theMatchUrl, RuntimeResourceDefinition resourceDef) {
+ SearchParameterMap paramMap = new SearchParameterMap();
+ List parameters = translateMatchUrl(theMatchUrl);
+
+ ArrayListMultimap nameToParamLists = ArrayListMultimap.create();
+ for (NameValuePair next : parameters) {
+ if (isBlank(next.getValue())) {
+ continue;
+ }
+
+ String paramName = next.getName();
+ String qualifier = null;
+ for (int i = 0; i < paramName.length(); i++) {
+ switch (paramName.charAt(i)) {
+ case '.':
+ case ':':
+ qualifier = paramName.substring(i);
+ paramName = paramName.substring(0, i);
+ i = Integer.MAX_VALUE - 1;
+ break;
+ }
+ }
+
+ QualifiedParamList paramList = QualifiedParamList.splitQueryStringByCommasIgnoreEscape(qualifier, next.getValue());
+ nameToParamLists.put(paramName, paramList);
+ }
+
+ for (String nextParamName : nameToParamLists.keySet()) {
+ List paramList = nameToParamLists.get(nextParamName);
+ if (Constants.PARAM_LASTUPDATED.equals(nextParamName)) {
+ if (paramList != null && paramList.size() > 0) {
+ if (paramList.size() > 2) {
+ throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - Can not have more than 2 " + Constants.PARAM_LASTUPDATED + " parameter repetitions");
+ } else {
+ DateRangeParam p1 = new DateRangeParam();
+ p1.setValuesAsQueryTokens(paramList);
+ paramMap.setLastUpdated(p1);
+ }
+ }
+ continue;
+ }
+
+ if (Constants.PARAM_COUNT.equals(nextParamName)) {
+ if (paramList.size() > 0 && paramList.get(0).size() > 0) {
+ String intString = paramList.get(0).get(0);
+ try {
+ paramMap.setCount(Integer.parseInt(intString));
+ } catch (NumberFormatException e) {
+ throw new InvalidRequestException("Invalid " + Constants.PARAM_COUNT + " value: " + intString);
+ }
+ }
+ continue;
+ }
+
+ if (RESOURCE_META_PARAMS.containsKey(nextParamName)) {
+ if (isNotBlank(paramList.get(0).getQualifier()) && paramList.get(0).getQualifier().startsWith(".")) {
+ throw new InvalidRequestException("Invalid parameter chain: " + nextParamName + paramList.get(0).getQualifier());
+ }
+ IQueryParameterAnd> type = newInstanceAnd(nextParamName);
+ type.setValuesAsQueryTokens((paramList));
+ paramMap.add(nextParamName, type);
+ } else if (nextParamName.startsWith("_")) {
+ // ignore these since they aren't search params (e.g. _sort)
+ } else {
+ RuntimeSearchParam paramDef = resourceDef.getSearchParam(nextParamName);
+ if (paramDef == null) {
+ throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - Resource type " + resourceDef.getName() + " does not have a parameter with name: " + nextParamName);
+ }
+
+ IQueryParameterAnd> param = MethodUtil.parseQueryParams(paramDef, nextParamName, paramList);
+ paramMap.add(nextParamName, param);
+ }
+ }
+ return paramMap;
+ }
+
+ public static void validateResourceType(BaseHasResource theEntity, String theResourceName) {
+ if (!theResourceName.equals(theEntity.getResourceType())) {
+ throw new ResourceNotFoundException("Resource with ID " + theEntity.getIdDt().getIdPart() + " exists but it is not of type " + theResourceName + ", found resource of type " + theEntity.getResourceType());
+ }
}
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java
index 1bec9df1921..126fc47f0fb 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java
@@ -34,32 +34,39 @@ import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
public class DaoConfig {
- private boolean myAllowMultipleDelete;
+ // ***
+ // update setter javadoc if default changes
+ // ***
+ private boolean myAllowInlineMatchUrlReferences = false;
+
+ private boolean myAllowMultipleDelete;
private int myHardSearchLimit = 1000;
private int myHardTagListLimit = 1000;
private int myIncludeLimit = 2000;
+
+ // ***
+ // update setter javadoc if default changes
+ // ***
+ private boolean myIndexContainedResources = true;
+
private List myInterceptors;
private ResourceEncodingEnum myResourceEncoding = ResourceEncodingEnum.JSONC;
private boolean mySchedulingDisabled;
private boolean mySubscriptionEnabled;
private long mySubscriptionPollDelay = 1000;
private Long mySubscriptionPurgeInactiveAfterMillis;
-
/**
* See {@link #setIncludeLimit(int)}
*/
public int getHardSearchLimit() {
return myHardSearchLimit;
}
-
public int getHardTagListLimit() {
return myHardTagListLimit;
}
-
public int getIncludeLimit() {
return myIncludeLimit;
}
-
/**
* Returns the interceptors which will be notified of operations.
*
@@ -84,10 +91,25 @@ public class DaoConfig {
return mySubscriptionPurgeInactiveAfterMillis;
}
+ /**
+ * @see #setAllowInlineMatchUrlReferences(boolean)
+ */
+ public boolean isAllowInlineMatchUrlReferences() {
+ return myAllowInlineMatchUrlReferences;
+ }
+
public boolean isAllowMultipleDelete() {
return myAllowMultipleDelete;
}
+ /**
+ * Should contained IDs be indexed the same way that non-contained IDs are (default is
+ * true
)
+ */
+ public boolean isIndexContainedResources() {
+ return myIndexContainedResources;
+ }
+
public boolean isSchedulingDisabled() {
return mySchedulingDisabled;
}
@@ -99,6 +121,20 @@ public class DaoConfig {
return mySubscriptionEnabled;
}
+ /**
+ * Should references containing match URLs be resolved and replaced in create and update operations. For
+ * example, if this property is set to true and a resource is created containing a reference
+ * to "Patient?identifier=12345", this is reference match URL will be resolved and replaced according
+ * to the usual match URL rules.
+ *
+ * Default is false for now, as this is an experimental feature.
+ *
+ * @since 1.5
+ */
+ public void setAllowInlineMatchUrlReferences(boolean theAllowInlineMatchUrlReferences) {
+ myAllowInlineMatchUrlReferences = theAllowInlineMatchUrlReferences;
+ }
+
public void setAllowMultipleDelete(boolean theAllowMultipleDelete) {
myAllowMultipleDelete = theAllowMultipleDelete;
}
@@ -120,6 +156,14 @@ public class DaoConfig {
myIncludeLimit = theIncludeLimit;
}
+ /**
+ * Should contained IDs be indexed the same way that non-contained IDs are (default is
+ * true
)
+ */
+ public void setIndexContainedResources(boolean theIndexContainedResources) {
+ myIndexContainedResources = theIndexContainedResources;
+ }
+
/**
* This may be used to optionally register server interceptors directly against the DAOs.
*
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IForcedIdDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IForcedIdDao.java
new file mode 100644
index 00000000000..5abd3907349
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IForcedIdDao.java
@@ -0,0 +1,34 @@
+package ca.uhn.fhir.jpa.dao.data;
+
+/*
+ * #%L
+ * HAPI FHIR JPA Server
+ * %%
+ * Copyright (C) 2014 - 2016 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.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+import ca.uhn.fhir.jpa.entity.ForcedId;
+
+public interface IForcedIdDao extends JpaRepository {
+
+ @Query("SELECT f FROM ForcedId f WHERE f.myResourcePid = :resource_pid")
+ public ForcedId findByResourcePid(@Param("resource_pid") Long theResourcePid);
+
+}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3.java
index 2e49a1d6f26..50a8a37ee7a 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3.java
@@ -462,7 +462,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao {
FhirTerser terser = getContext().newTerser();
for (DaoMethodOutcome nextOutcome : idToPersistedOutcome.values()) {
- IBaseResource nextResource = (IBaseResource) nextOutcome.getResource();
+ IBaseResource nextResource = nextOutcome.getResource();
if (nextResource == null) {
continue;
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ForcedId.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ForcedId.java
index 2653f61afb1..e21fb56ef32 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ForcedId.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ForcedId.java
@@ -35,7 +35,8 @@ import javax.persistence.UniqueConstraint;
//@formatter:off
@Entity()
@Table(name = "HFJ_FORCED_ID", uniqueConstraints = {
- @UniqueConstraint(name = "IDX_FORCEDID", columnNames = {"FORCED_ID"})
+ @UniqueConstraint(name = "IDX_FORCEDID", columnNames = {"FORCED_ID"}),
+ @UniqueConstraint(name = "IDX_FORCEDID_RESID", columnNames = {"RESOURCE_PID"})
})
@NamedQueries(value = {
@NamedQuery(name = "Q_GET_FORCED_ID", query = "SELECT f FROM ForcedId f WHERE myForcedId = :ID")
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamCoords.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamCoords.java
index 52666ec75c6..1fd44201d30 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamCoords.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamCoords.java
@@ -23,6 +23,7 @@ package ca.uhn.fhir.jpa.entity;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
+import javax.persistence.Index;
import javax.persistence.Table;
import org.apache.commons.lang3.builder.EqualsBuilder;
@@ -34,9 +35,8 @@ import org.hibernate.search.annotations.Field;
//@formatter:off
@Embeddable
@Entity
-@Table(name = "HFJ_SPIDX_COORDS" /* , indexes = { @Index(name = "IDX_SP_TOKEN", columnList = "SP_SYSTEM,SP_VALUE") } */)
-@org.hibernate.annotations.Table(appliesTo = "HFJ_SPIDX_COORDS", indexes = {
- @org.hibernate.annotations.Index(name = "IDX_SP_COORDS", columnNames = { "RES_TYPE", "SP_NAME", "SP_LATITUDE" })
+@Table(name = "HFJ_SPIDX_COORDS", indexes = {
+ @Index(name = "IDX_SP_COORDS", columnList = "RES_TYPE,SP_NAME,SP_LATITUDE,SP_LONGITUDE")
})
//@formatter:on
public class ResourceIndexedSearchParamCoords extends BaseResourceIndexedSearchParam {
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java
index 8c04aa591ba..73604ef8c37 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java
@@ -144,6 +144,9 @@ public class ResourceTable extends BaseHasResource implements Serializable {
//@formatter:on
private String myContentText;
+ @Column(name = "HAS_CONTAINED", nullable = true)
+ private boolean myHasContainedResource;
+
@Column(name = "SP_HAS_LINKS")
private boolean myHasLinks;
@@ -158,6 +161,9 @@ public class ResourceTable extends BaseHasResource implements Serializable {
@Column(name = "SP_INDEX_STATUS", nullable = true)
private Long myIndexStatus;
+ @Column(name = "IS_CONTAINED", nullable = true)
+ private boolean myIsContainedResource;
+
@Column(name = "RES_LANGUAGE", length = MAX_LANGUAGE_LENGTH, nullable = true)
private String myLanguage;
@@ -173,13 +179,13 @@ public class ResourceTable extends BaseHasResource implements Serializable {
@Column(name = "SP_COORDS_PRESENT")
private boolean myParamsCoordsPopulated;
-
+
@OneToMany(mappedBy = "myResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
private Collection myParamsDate;
@Column(name = "SP_DATE_PRESENT")
private boolean myParamsDatePopulated;
-
+
@OneToMany(mappedBy = "myResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
private Collection myParamsNumber;
@@ -340,10 +346,18 @@ public class ResourceTable extends BaseHasResource implements Serializable {
return false;
}
+ public boolean isHasContainedResource() {
+ return myHasContainedResource;
+ }
+
public boolean isHasLinks() {
return myHasLinks;
}
+ public boolean isIsContainedResource() {
+ return myIsContainedResource;
+ }
+
public boolean isParamsCoordsPopulated() {
return myParamsCoordsPopulated;
}
@@ -376,6 +390,10 @@ public class ResourceTable extends BaseHasResource implements Serializable {
myContentText = theContentText;
}
+ public void setHasContainedResource(boolean theHasContainedResource) {
+ myHasContainedResource = theHasContainedResource;
+ }
+
public void setHasLinks(boolean theHasLinks) {
myHasLinks = theHasLinks;
}
@@ -388,6 +406,10 @@ public class ResourceTable extends BaseHasResource implements Serializable {
myIndexStatus = theIndexStatus;
}
+ public void setIsContainedResource(boolean theIsContainedResource) {
+ myIsContainedResource = theIsContainedResource;
+ }
+
public void setLanguage(String theLanguage) {
if (defaultString(theLanguage).length() > MAX_LANGUAGE_LENGTH) {
throw new UnprocessableEntityException("Language exceeds maximum length of " + MAX_LANGUAGE_LENGTH + " chars: " + theLanguage);
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaTest.java
index 14261c933a2..c4e36e56d99 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaTest.java
@@ -1,8 +1,9 @@
package ca.uhn.fhir.jpa.dao;
+import static org.mockito.Mockito.mock;
+
import java.io.IOException;
import java.io.InputStream;
-import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
@@ -12,21 +13,29 @@ import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.AfterClass;
+import org.junit.Before;
import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
import ca.uhn.fhir.rest.server.IBundleProvider;
+import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
public class BaseJpaTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseJpaTest.class);
+ protected ServletRequestDetails mySrd;
@SuppressWarnings({ "rawtypes" })
protected List toList(IBundleProvider theSearch) {
return theSearch.getResources(0, theSearch.size());
}
+ @Before
+ public void beforeCreateSrd() {
+ mySrd = mock(ServletRequestDetails.class);
+ }
+
protected List toUnqualifiedVersionlessIds(Bundle theFound) {
List retVal = new ArrayList();
for (Entry next : theFound.getEntry()) {
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/BaseJpaDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/BaseJpaDstu3Test.java
index ffb25854525..78707accb4e 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/BaseJpaDstu3Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/BaseJpaDstu3Test.java
@@ -47,6 +47,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallback;
@@ -239,14 +240,14 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
public TransactionTemplate newTxTemplate() {
TransactionTemplate retVal = new TransactionTemplate(myTxManager);
- retVal.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW);
+ retVal.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
retVal.afterPropertiesSet();
return retVal;
}
public static void purgeDatabase(final EntityManager entityManager, PlatformTransactionManager theTxManager) {
TransactionTemplate txTemplate = new TransactionTemplate(theTxManager);
- txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRED);
+ txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
txTemplate.execute(new TransactionCallback() {
@Override
public Void doInTransaction(TransactionStatus theStatus) {
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3ContainedTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3ContainedTest.java
new file mode 100644
index 00000000000..bc8cd77dd02
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3ContainedTest.java
@@ -0,0 +1,59 @@
+package ca.uhn.fhir.jpa.dao.dstu3;
+
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.junit.Assert.assertThat;
+
+import org.hl7.fhir.dstu3.model.Observation;
+import org.hl7.fhir.dstu3.model.Patient;
+import org.hl7.fhir.dstu3.model.Reference;
+import org.hl7.fhir.instance.model.api.IIdType;
+import org.junit.Test;
+
+import ca.uhn.fhir.jpa.dao.SearchParameterMap;
+import ca.uhn.fhir.rest.param.TokenParam;
+import ca.uhn.fhir.rest.param.TokenParamModifier;
+import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
+
+public class FhirResourceDaoDstu3ContainedTest extends BaseJpaDstu3Test {
+ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3ContainedTest.class);
+
+ @Test
+ public void before() {
+ myDaoConfig.setIndexContainedResources(true);
+ }
+
+ @Test
+ public void testIndexContained() {
+ Patient p = new Patient();
+ p.setId("#some_patient");
+ p.addName().addFamily("MYFAMILY").addGiven("MYGIVEN");
+
+ Observation o1 = new Observation();
+ o1.getCode().setText("Some Observation");
+ o1.setSubject(new Reference(p));
+ IIdType oid1 = myObservationDao.create(o1, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+
+ Observation o2 = new Observation();
+ o2.getCode().setText("Some Observation");
+ o2.setSubject(new Reference(p));
+ IIdType oid2 = myObservationDao.create(o2, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+
+ Patient p2 = new Patient();
+ p2.addName().addFamily("MYFAMILY").addGiven("MYGIVEN");
+ IIdType pid2 = myPatientDao.create(p2, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+
+ ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(o2));
+
+
+ SearchParameterMap map;
+
+// map = new SearchParameterMap();
+// map.add(Observation.SP_CODE, new TokenParam(null, "some observation").setModifier(TokenParamModifier.TEXT));
+// assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(id1, id2)));
+
+ }
+
+
+ // TODO: make sure match URLs don't delete
+
+}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchFtTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchFtTest.java
index 508da9b26b9..33eff79c03c 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchFtTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchFtTest.java
@@ -31,6 +31,7 @@ import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.StringOrListParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenParam;
+import ca.uhn.fhir.rest.param.TokenParamModifier;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
@@ -46,31 +47,35 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
obs1.setStatus(ObservationStatus.FINAL);
obs1.setValue(new Quantity(123));
obs1.setComments("obs1");
- IIdType id1 = myObservationDao.create(obs1, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType id1 = myObservationDao.create(obs1, mySrd).getId().toUnqualifiedVersionless();
Observation obs2 = new Observation();
obs2.getCode().setText("Diastolic Blood Pressure");
obs2.setStatus(ObservationStatus.FINAL);
obs2.setValue(new Quantity(81));
- IIdType id2 = myObservationDao.create(obs2, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType id2 = myObservationDao.create(obs2, mySrd).getId().toUnqualifiedVersionless();
SearchParameterMap map;
map = new SearchParameterMap();
- map.add(Observation.SP_CODE, new TokenParam(null, "blood").setText(true));
+ map.add(Observation.SP_CODE, new TokenParam(null, "blood").setModifier(TokenParamModifier.TEXT));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(id1, id2)));
map = new SearchParameterMap();
- map.add(Observation.SP_CODE, new TokenParam(null, "blood").setText(true));
+ map.add(Observation.SP_CODE, new TokenParam(null, "blood").setModifier(TokenParamModifier.TEXT));
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), empty());
map = new SearchParameterMap();
- map.add(Observation.SP_CODE, new TokenParam(null, "blood").setText(true));
+ map.add(Observation.SP_CODE, new TokenParam(null, "blood").setModifier(TokenParamModifier.TEXT));
map.add(Constants.PARAM_CONTENT, new StringParam("obs1"));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(id1)));
}
+ private ServletRequestDetails mockSrd() {
+ return new ServletRequestDetails();
+ }
+
@Test
@Ignore
public void testStringTextSearch() {
@@ -78,13 +83,13 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
obs1.getCode().setText("AAAAA");
obs1.setValue(new StringType("Systolic Blood Pressure"));
obs1.setStatus(ObservationStatus.FINAL);
- IIdType id1 = myObservationDao.create(obs1, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType id1 = myObservationDao.create(obs1, mockSrd()).getId().toUnqualifiedVersionless();
Observation obs2 = new Observation();
obs1.getCode().setText("AAAAA");
obs1.setValue(new StringType("Diastolic Blood Pressure"));
obs2.setStatus(ObservationStatus.FINAL);
- IIdType id2 = myObservationDao.create(obs2, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType id2 = myObservationDao.create(obs2, mockSrd()).getId().toUnqualifiedVersionless();
SearchParameterMap map;
@@ -99,7 +104,7 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
public void testSuggestIgnoresBase64Content() {
Patient patient = new Patient();
patient.addName().addFamily("testSuggest");
- IIdType ptId = myPatientDao.create(patient, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType ptId = myPatientDao.create(patient, mockSrd()).getId().toUnqualifiedVersionless();
Media med = new Media();
med.getSubject().setReferenceElement(ptId);
@@ -107,7 +112,7 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
med.getContent().setContentType("LCws");
med.getContent().setDataElement(new Base64BinaryType(new byte[] {44,44,44,44,44,44,44,44}));
med.getContent().setTitle("bbbb syst");
- myMediaDao.create(med, new ServletRequestDetails());
+ myMediaDao.create(med, mockSrd());
ourLog.info(myFhirCtx.newJsonParser().encodeResourceToString(med));
List output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "press");
@@ -139,35 +144,35 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
public void testSuggest() {
Patient patient = new Patient();
patient.addName().addFamily("testSuggest");
- IIdType ptId = myPatientDao.create(patient, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType ptId = myPatientDao.create(patient, mockSrd()).getId().toUnqualifiedVersionless();
Observation obs = new Observation();
obs.getSubject().setReferenceElement(ptId);
obs.getCode().setText("ZXCVBNM ASDFGHJKL QWERTYUIOPASDFGHJKL");
- myObservationDao.create(obs, new ServletRequestDetails());
+ myObservationDao.create(obs, mockSrd());
obs = new Observation();
obs.getSubject().setReferenceElement(ptId);
obs.getCode().setText("MNBVCXZ");
- myObservationDao.create(obs, new ServletRequestDetails());
+ myObservationDao.create(obs, mockSrd());
obs = new Observation();
obs.getSubject().setReferenceElement(ptId);
obs.getCode().setText("ZXC HELLO");
obs.addComponent().getCode().setText("HHHHHHHHHH");
- myObservationDao.create(obs, new ServletRequestDetails());
+ myObservationDao.create(obs, mockSrd());
/*
* These shouldn't match since they're for another patient
*/
patient = new Patient();
patient.addName().addFamily("testSuggest2");
- IIdType ptId2 = myPatientDao.create(patient, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType ptId2 = myPatientDao.create(patient, mockSrd()).getId().toUnqualifiedVersionless();
Observation obs2 = new Observation();
obs2.getSubject().setReferenceElement(ptId2);
obs2.getCode().setText("ZXCVBNMZZ");
- myObservationDao.create(obs2, new ServletRequestDetails());
+ myObservationDao.create(obs2, mockSrd());
List output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "ZXCVBNM");
ourLog.info("Found: " + output);
@@ -212,7 +217,7 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
patient = new Patient();
patient.getText().setDivAsString("DIVAAA
");
patient.addName().addGiven("NAMEAAA");
- IIdType pId1 = myPatientDao.create(patient, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType pId1 = myPatientDao.create(patient, mockSrd()).getId().toUnqualifiedVersionless();
map = new SearchParameterMap();
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA"));
@@ -230,7 +235,7 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
patient.setId(pId1);
patient.getText().setDivAsString("DIVBBB
");
patient.addName().addGiven("NAMEBBB");
- myPatientDao.update(patient, new ServletRequestDetails());
+ myPatientDao.update(patient, mockSrd());
map = new SearchParameterMap();
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA"));
@@ -254,19 +259,19 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
public void testEverythingInstanceWithContentFilter() {
Patient pt1 = new Patient();
pt1.addName().addFamily("Everything").addGiven("Arthur");
- IIdType ptId1 = myPatientDao.create(pt1, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType ptId1 = myPatientDao.create(pt1, mockSrd()).getId().toUnqualifiedVersionless();
Patient pt2 = new Patient();
pt2.addName().addFamily("Everything").addGiven("Arthur");
- IIdType ptId2 = myPatientDao.create(pt2, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType ptId2 = myPatientDao.create(pt2, mockSrd()).getId().toUnqualifiedVersionless();
Device dev1 = new Device();
dev1.setManufacturer("Some Manufacturer");
- IIdType devId1 = myDeviceDao.create(dev1, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType devId1 = myDeviceDao.create(dev1, mockSrd()).getId().toUnqualifiedVersionless();
Device dev2 = new Device();
dev2.setManufacturer("Some Manufacturer 2");
- myDeviceDao.create(dev2, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ myDeviceDao.create(dev2, mockSrd()).getId().toUnqualifiedVersionless();
Observation obs1 = new Observation();
obs1.getText().setDivAsString("OBSTEXT1
");
@@ -274,19 +279,19 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
obs1.getCode().addCoding().setCode("CODE1");
obs1.setValue(new StringType("obsvalue1"));
obs1.getDevice().setReferenceElement(devId1);
- IIdType obsId1 = myObservationDao.create(obs1, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType obsId1 = myObservationDao.create(obs1, mockSrd()).getId().toUnqualifiedVersionless();
Observation obs2 = new Observation();
obs2.getSubject().setReferenceElement(ptId1);
obs2.getCode().addCoding().setCode("CODE2");
obs2.setValue(new StringType("obsvalue2"));
- IIdType obsId2 = myObservationDao.create(obs2, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType obsId2 = myObservationDao.create(obs2, mockSrd()).getId().toUnqualifiedVersionless();
Observation obs3 = new Observation();
obs3.getSubject().setReferenceElement(ptId2);
obs3.getCode().addCoding().setCode("CODE3");
obs3.setValue(new StringType("obsvalue3"));
- IIdType obsId3 = myObservationDao.create(obs3, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType obsId3 = myObservationDao.create(obs3, mockSrd()).getId().toUnqualifiedVersionless();
HttpServletRequest request;
List actual;
@@ -297,16 +302,16 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1")));
- actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, param, null, new ServletRequestDetails()));
+ actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, param, null, mockSrd()));
assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId1, devId1)));
param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("obstext1")));
- actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, null, param, new ServletRequestDetails()));
+ actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, null, param, mockSrd()));
assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId1, devId1)));
request = mock(HttpServletRequest.class);
- actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, null, null, new ServletRequestDetails()));
+ actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, null, null, mockSrd()));
assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId1, obsId2, devId1)));
/*
@@ -317,12 +322,12 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
obs4.getSubject().setReferenceElement(ptId1);
obs4.getCode().addCoding().setCode("CODE1");
obs4.setValue(new StringType("obsvalue1"));
- IIdType obsId4 = myObservationDao.create(obs4, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType obsId4 = myObservationDao.create(obs4, mockSrd()).getId().toUnqualifiedVersionless();
assertNotEquals(obsId1.getIdPart(), obsId4.getIdPart(), devId1);
param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1")));
- actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, param, null, new ServletRequestDetails()));
+ actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, param, null, mockSrd()));
assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId1, obsId4, devId1)));
/*
@@ -334,11 +339,11 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
obs1.getSubject().setReferenceElement(ptId1);
obs1.getCode().addCoding().setCode("CODE2");
obs1.setValue(new StringType("obsvalue2"));
- myObservationDao.update(obs1, new ServletRequestDetails());
+ myObservationDao.update(obs1, mockSrd());
param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1")));
- actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, param, null, new ServletRequestDetails()));
+ actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, param, null, mockSrd()));
assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId4)));
}
@@ -347,38 +352,38 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
public void testEverythingTypeWithContentFilter() {
Patient pt1 = new Patient();
pt1.addName().addFamily("Everything").addGiven("Arthur");
- IIdType ptId1 = myPatientDao.create(pt1, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType ptId1 = myPatientDao.create(pt1, mockSrd()).getId().toUnqualifiedVersionless();
Patient pt2 = new Patient();
pt2.addName().addFamily("Everything").addGiven("Arthur");
- IIdType ptId2 = myPatientDao.create(pt2, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType ptId2 = myPatientDao.create(pt2, mockSrd()).getId().toUnqualifiedVersionless();
Device dev1 = new Device();
dev1.setManufacturer("Some Manufacturer");
- IIdType devId1 = myDeviceDao.create(dev1, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType devId1 = myDeviceDao.create(dev1, mockSrd()).getId().toUnqualifiedVersionless();
Device dev2 = new Device();
dev2.setManufacturer("Some Manufacturer 2");
- IIdType devId2 = myDeviceDao.create(dev2, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ myDeviceDao.create(dev2, mockSrd()).getId().toUnqualifiedVersionless();
Observation obs1 = new Observation();
obs1.getSubject().setReferenceElement(ptId1);
obs1.getCode().addCoding().setCode("CODE1");
obs1.setValue(new StringType("obsvalue1"));
obs1.getDevice().setReferenceElement(devId1);
- IIdType obsId1 = myObservationDao.create(obs1, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType obsId1 = myObservationDao.create(obs1, mockSrd()).getId().toUnqualifiedVersionless();
Observation obs2 = new Observation();
obs2.getSubject().setReferenceElement(ptId1);
obs2.getCode().addCoding().setCode("CODE2");
obs2.setValue(new StringType("obsvalue2"));
- IIdType obsId2 = myObservationDao.create(obs2, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType obsId2 = myObservationDao.create(obs2, mockSrd()).getId().toUnqualifiedVersionless();
Observation obs3 = new Observation();
obs3.getSubject().setReferenceElement(ptId2);
obs3.getCode().addCoding().setCode("CODE3");
obs3.setValue(new StringType("obsvalue3"));
- IIdType obsId3 = myObservationDao.create(obs3, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType obsId3 = myObservationDao.create(obs3, mockSrd()).getId().toUnqualifiedVersionless();
HttpServletRequest request;
List actual;
@@ -389,11 +394,11 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1")));
- actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientTypeEverything(request, null, null, null, param, null, new ServletRequestDetails()));
+ actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientTypeEverything(request, null, null, null, param, null, mockSrd()));
assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId1, devId1)));
request = mock(HttpServletRequest.class);
- actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientTypeEverything(request, null, null, null, null, null, new ServletRequestDetails()));
+ actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientTypeEverything(request, null, null, null, null, null, mockSrd()));
assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId1, obsId2, devId1, ptId2, obsId3)));
/*
@@ -404,12 +409,12 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
obs4.getSubject().setReferenceElement(ptId1);
obs4.getCode().addCoding().setCode("CODE1");
obs4.setValue(new StringType("obsvalue1"));
- IIdType obsId4 = myObservationDao.create(obs4, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType obsId4 = myObservationDao.create(obs4, mockSrd()).getId().toUnqualifiedVersionless();
assertNotEquals(obsId1.getIdPart(), obsId4.getIdPart(), devId1);
param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1")));
- actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientTypeEverything(request, null, null, null, param, null, new ServletRequestDetails()));
+ actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientTypeEverything(request, null, null, null, param, null, mockSrd()));
assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId1, obsId4, devId1)));
/*
@@ -421,11 +426,11 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
obs1.getSubject().setReferenceElement(ptId1);
obs1.getCode().addCoding().setCode("CODE2");
obs1.setValue(new StringType("obsvalue2"));
- myObservationDao.update(obs1, new ServletRequestDetails());
+ myObservationDao.update(obs1, mockSrd());
param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1")));
- actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientTypeEverything(request, null, null, null, param, null, new ServletRequestDetails()));
+ actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientTypeEverything(request, null, null, null, param, null, mockSrd()));
assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId4)));
}
@@ -443,7 +448,7 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
patient = new Patient();
patient.getText().setDivAsString("DIVAAA
");
patient.addName().addGiven("NAMEAAA");
- IIdType pId1 = myPatientDao.create(patient, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType pId1 = myPatientDao.create(patient, mockSrd()).getId().toUnqualifiedVersionless();
map = new SearchParameterMap();
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA"));
@@ -461,7 +466,7 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
patient.setId(pId1);
patient.getText().setDivAsString("DIVBBB
");
patient.addName().addGiven("NAMEBBB");
- myPatientDao.update(patient, null, false, new ServletRequestDetails());
+ myPatientDao.update(patient, null, false, mockSrd());
map = new SearchParameterMap();
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA"));
@@ -470,7 +475,7 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEBBB"));
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), not(contains(toValues(pId1))));
- myPatientDao.update(patient, null, true, new ServletRequestDetails());
+ myPatientDao.update(patient, null, true, mockSrd());
map = new SearchParameterMap();
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA"));
@@ -498,18 +503,18 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
Patient patient = new Patient();
patient.addName().addGiven(methodName);
patient.addAddress().addLine("My fulltext address");
- pId1 = myPatientDao.create(patient, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ pId1 = myPatientDao.create(patient, mockSrd()).getId().toUnqualifiedVersionless();
}
Observation obs = new Observation();
obs.getSubject().setReferenceElement(pId1);
obs.setValue(new StringType("This is the FULLtext of the observation"));
- IIdType oId1 = myObservationDao.create(obs, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType oId1 = myObservationDao.create(obs, mockSrd()).getId().toUnqualifiedVersionless();
obs = new Observation();
obs.getSubject().setReferenceElement(pId1);
obs.setValue(new StringType("Another fullText"));
- IIdType oId2 = myObservationDao.create(obs, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
+ IIdType oId2 = myObservationDao.create(obs, mockSrd()).getId().toUnqualifiedVersionless();
List patients;
SearchParameterMap params;
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchNoFtTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchNoFtTest.java
index e56a22b1a9c..1c3df054e74 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchNoFtTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchNoFtTest.java
@@ -23,7 +23,6 @@ import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
-import org.hl7.fhir.dstu3.model.BaseResource;
import org.hl7.fhir.dstu3.model.CodeType;
import org.hl7.fhir.dstu3.model.ConceptMap;
import org.hl7.fhir.dstu3.model.ContactPoint.ContactPointSystem;
@@ -52,6 +51,7 @@ import org.hl7.fhir.dstu3.model.Subscription.SubscriptionStatus;
import org.hl7.fhir.dstu3.model.Substance;
import org.hl7.fhir.dstu3.model.TemporalPrecisionEnum;
import org.hl7.fhir.dstu3.model.ValueSet;
+import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.Ignore;
@@ -586,21 +586,21 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
}
{
Map params = new HashMap();
- params.put(BaseResource.SP_RES_LANGUAGE, new StringParam("en_CA"));
+ params.put(IAnyResource.SP_RES_LANGUAGE, new StringParam("en_CA"));
List patients = toList(myPatientDao.search(params));
assertEquals(1, patients.size());
assertEquals(id1.toUnqualifiedVersionless(), patients.get(0).getIdElement().toUnqualifiedVersionless());
}
{
Map params = new HashMap();
- params.put(BaseResource.SP_RES_LANGUAGE, new StringParam("en_US"));
+ params.put(IAnyResource.SP_RES_LANGUAGE, new StringParam("en_US"));
List patients = toList(myPatientDao.search(params));
assertEquals(1, patients.size());
assertEquals(id2.toUnqualifiedVersionless(), patients.get(0).getIdElement().toUnqualifiedVersionless());
}
{
Map params = new HashMap();
- params.put(BaseResource.SP_RES_LANGUAGE, new StringParam("en_GB"));
+ params.put(IAnyResource.SP_RES_LANGUAGE, new StringParam("en_GB"));
List patients = toList(myPatientDao.search(params));
assertEquals(0, patients.size());
}
@@ -629,18 +629,18 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
}
{
SearchParameterMap params = new SearchParameterMap();
- params.add(BaseResource.SP_RES_LANGUAGE, new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("en_US")));
+ params.add(IAnyResource.SP_RES_LANGUAGE, new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("en_US")));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1, id2));
}
{
SearchParameterMap params = new SearchParameterMap();
- params.add(BaseResource.SP_RES_LANGUAGE, new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("en_US")));
+ params.add(IAnyResource.SP_RES_LANGUAGE, new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("en_US")));
params.setLastUpdated(new DateRangeParam(betweenTime, null));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id2));
}
{
SearchParameterMap params = new SearchParameterMap();
- params.add(BaseResource.SP_RES_LANGUAGE, new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("ZZZZ")));
+ params.add(IAnyResource.SP_RES_LANGUAGE, new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("ZZZZ")));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1));
}
{
@@ -648,7 +648,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
StringAndListParam and = new StringAndListParam();
and.addAnd(new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("ZZZZ")));
and.addAnd(new StringOrListParam().addOr(new StringParam("en_CA")));
- params.add(BaseResource.SP_RES_LANGUAGE, and);
+ params.add(IAnyResource.SP_RES_LANGUAGE, and);
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1));
}
{
@@ -656,7 +656,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
StringAndListParam and = new StringAndListParam();
and.addAnd(new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("ZZZZ")));
and.addAnd(new StringOrListParam().addOr(new StringParam("ZZZZZ")));
- params.add(BaseResource.SP_RES_LANGUAGE, and);
+ params.add(IAnyResource.SP_RES_LANGUAGE, and);
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), empty());
}
{
@@ -664,7 +664,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
StringAndListParam and = new StringAndListParam();
and.addAnd(new StringOrListParam().addOr(new StringParam("ZZZZZ")));
and.addAnd(new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("ZZZZ")));
- params.add(BaseResource.SP_RES_LANGUAGE, and);
+ params.add(IAnyResource.SP_RES_LANGUAGE, and);
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), empty());
}
{
@@ -672,7 +672,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
StringAndListParam and = new StringAndListParam();
and.addAnd(new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("ZZZZ")));
and.addAnd(new StringOrListParam().addOr(new StringParam("")).addOr(new StringParam(null)));
- params.add(BaseResource.SP_RES_LANGUAGE, and);
+ params.add(IAnyResource.SP_RES_LANGUAGE, and);
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1));
}
{
@@ -681,7 +681,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
StringAndListParam and = new StringAndListParam();
and.addAnd(new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("ZZZZ")));
and.addAnd(new StringOrListParam().addOr(new StringParam("")).addOr(new StringParam(null)));
- params.add(BaseResource.SP_RES_LANGUAGE, and);
+ params.add(IAnyResource.SP_RES_LANGUAGE, and);
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1));
}
{
@@ -689,7 +689,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
StringAndListParam and = new StringAndListParam();
and.addAnd(new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("ZZZZ")));
and.addAnd(new StringOrListParam().addOr(new StringParam("")).addOr(new StringParam(null)));
- params.add(BaseResource.SP_RES_LANGUAGE, and);
+ params.add(IAnyResource.SP_RES_LANGUAGE, and);
params.add("_id", new StringParam(id1.getIdPart()));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1));
}
@@ -767,8 +767,6 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
@Test
public void testSearchLastUpdatedParamWithComparator() throws InterruptedException {
- String methodName = "testSearchLastUpdatedParamWithComparator";
-
IIdType id0;
{
Patient patient = new Patient();
@@ -781,7 +779,6 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
long start = System.currentTimeMillis();
Thread.sleep(sleep);
- DateTimeType beforeAny = new DateTimeType(new Date(), TemporalPrecisionEnum.MILLI);
IIdType id1a;
{
Patient patient = new Patient();
@@ -815,12 +812,12 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), containsInAnyOrder(id1a, id1b));
map = new SearchParameterMap();
- map.setLastUpdated(new DateRangeParam(new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, startDateTime), new DateParam(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS, endDateTime)));
+ map.setLastUpdated(new DateRangeParam(new DateParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, startDateTime), new DateParam(ParamPrefixEnum.LESSTHAN_OR_EQUALS, endDateTime)));
ourLog.info("Searching: {}", map.getLastUpdated());
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), containsInAnyOrder(id1a, id1b));
map = new SearchParameterMap();
- map.setLastUpdated(new DateRangeParam(new DateParam(QuantityCompararatorEnum.GREATERTHAN, startDateTime), new DateParam(QuantityCompararatorEnum.LESSTHAN, endDateTime)));
+ map.setLastUpdated(new DateRangeParam(new DateParam(ParamPrefixEnum.GREATERTHAN, startDateTime), new DateParam(ParamPrefixEnum.LESSTHAN, endDateTime)));
ourLog.info("Searching: {}", map.getLastUpdated());
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), containsInAnyOrder(id1a, id1b));
@@ -1373,7 +1370,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
QuantityParam param;
Set found;
- param = new QuantityParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), null, null);
+ param = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), null, null);
found = myObservationDao.searchForIds("value-quantity", param);
int initialSize = found.size();
@@ -1384,19 +1381,19 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
myObservationDao.create(o, new ServletRequestDetails());
- param = new QuantityParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), null, null);
+ param = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), null, null);
found = myObservationDao.searchForIds("value-quantity", param);
assertEquals(1 + initialSize, found.size());
- param = new QuantityParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), null, methodName + "units");
+ param = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), null, methodName + "units");
found = myObservationDao.searchForIds("value-quantity", param);
assertEquals(1, found.size());
- param = new QuantityParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), "urn:bar:" + methodName, null);
+ param = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), "urn:bar:" + methodName, null);
found = myObservationDao.searchForIds("value-quantity", param);
assertEquals(1, found.size());
- param = new QuantityParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), "urn:bar:" + methodName, methodName + "units");
+ param = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, new BigDecimal("10"), "urn:bar:" + methodName, methodName + "units");
found = myObservationDao.searchForIds("value-quantity", param);
assertEquals(1, found.size());
@@ -1406,8 +1403,8 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
public void testSearchWithEmptySort() {
SearchParameterMap criteriaUrl = new SearchParameterMap();
DateRangeParam range = new DateRangeParam();
- range.setLowerBound(new DateParam(QuantityCompararatorEnum.GREATERTHAN, 1000000));
- range.setUpperBound(new DateParam(QuantityCompararatorEnum.LESSTHAN, 2000000));
+ range.setLowerBound(new DateParam(ParamPrefixEnum.GREATERTHAN, 1000000));
+ range.setUpperBound(new DateParam(ParamPrefixEnum.LESSTHAN, 2000000));
criteriaUrl.setLastUpdated(range);
criteriaUrl.setSort(new SortSpec(Constants.PARAM_LASTUPDATED, SortOrderEnum.ASC));
IBundleProvider results = myObservationDao.search(criteriaUrl);
@@ -1555,7 +1552,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
{
SearchParameterMap params = new SearchParameterMap();
- params.add(BaseResource.SP_RES_ID, new StringParam(orgId.getIdPart()));
+ params.add(IAnyResource.SP_RES_ID, new StringParam(orgId.getIdPart()));
params.addInclude(Organization.INCLUDE_PARTOF.asNonRecursive());
List resources = toUnqualifiedVersionlessIds(myOrganizationDao.search(params));
assertThat(resources, contains(orgId, parentOrgId));
@@ -1597,7 +1594,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
{
SearchParameterMap params = new SearchParameterMap();
- params.add(Organization.SP_RES_ID, new StringParam(orgId.getIdPart()));
+ params.add(IAnyResource.SP_RES_ID, new StringParam(orgId.getIdPart()));
params.addInclude(Organization.INCLUDE_PARTOF.asRecursive());
List resources = toUnqualifiedVersionlessIds(myOrganizationDao.search(params));
ourLog.info(resources.toString());
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3Test.java
index 76ff2f8b6ab..f79375cd079 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3Test.java
@@ -42,8 +42,10 @@ import org.hl7.fhir.dstu3.model.UriType;
import org.hl7.fhir.dstu3.model.ValueSet;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IIdType;
+import org.junit.After;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
+import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
@@ -112,7 +114,7 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
// Try making the resource unparseable
TransactionTemplate template = new TransactionTemplate(myTxManager);
- template.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW);
+ template.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
template.execute(new TransactionCallback() {
@Override
public ResourceTable doInTransaction(TransactionStatus theStatus) {
@@ -305,6 +307,100 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
}
+ @After
+ public void after() {
+ myDaoConfig.setAllowInlineMatchUrlReferences(false);
+ }
+
+ @Test
+ public void testTransactionCreateInlineMatchUrlWithOneMatch() {
+ String methodName = "testTransactionCreateInlineMatchUrlWithOneMatch";
+ Bundle request = new Bundle();
+
+ myDaoConfig.setAllowInlineMatchUrlReferences(true);
+
+ Patient p = new Patient();
+ p.addIdentifier().setSystem("urn:system").setValue(methodName);
+ p.setId("Patient/" + methodName);
+ IIdType id = myPatientDao.update(p, mySrd).getId();
+ ourLog.info("Created patient, got it: {}", id);
+
+ Observation o = new Observation();
+ o.getCode().setText("Some Observation");
+ o.getSubject().setReference("Patient?identifier=urn%3Asystem%7C" + methodName);
+ request.addEntry().setResource(o).getRequest().setMethod(HTTPVerb.POST);
+
+ Bundle resp = mySystemDao.transaction(myRequestDetails, request);
+ assertEquals(1, resp.getEntry().size());
+
+ BundleEntryComponent respEntry = resp.getEntry().get(0);
+ assertEquals(Constants.STATUS_HTTP_201_CREATED + " Created", respEntry.getResponse().getStatus());
+ assertThat(respEntry.getResponse().getLocation(), containsString("Observation/"));
+ assertThat(respEntry.getResponse().getLocation(), endsWith("/_history/1"));
+ assertEquals("1", respEntry.getResponse().getEtag());
+
+ o = myObservationDao.read(new IdType(respEntry.getResponse().getLocationElement()), mySrd);
+ assertEquals(id.toVersionless().getValue(), o.getSubject().getReference());
+ assertEquals("1", o.getIdElement().getVersionIdPart());
+
+ }
+
+ @Test
+ public void testTransactionCreateInlineMatchUrlWithNoMatches() {
+ String methodName = "testTransactionCreateInlineMatchUrlWithNoMatches";
+ Bundle request = new Bundle();
+
+ myDaoConfig.setAllowInlineMatchUrlReferences(true);
+
+ Patient p = new Patient();
+ p.addIdentifier().setSystem("urn:system").setValue(methodName);
+ myPatientDao.create(p, mySrd).getId();
+
+ p = new Patient();
+ p.addIdentifier().setSystem("urn:system").setValue(methodName);
+ myPatientDao.create(p, mySrd).getId();
+
+ Observation o = new Observation();
+ o.getCode().setText("Some Observation");
+ o.getSubject().setReference("Patient?identifier=urn%3Asystem%7C" + methodName);
+ request.addEntry().setResource(o).getRequest().setMethod(HTTPVerb.POST);
+
+ try {
+ mySystemDao.transaction(myRequestDetails, request);
+ fail();
+ } catch (InvalidRequestException e) {
+ assertEquals("Invalid match URL \"Patient?identifier=urn%3Asystem%7CtestTransactionCreateInlineMatchUrlWithNoMatches\" - Multiple resources match this search", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testTransactionCreateInlineMatchUrlWithTwoMatches() {
+ String methodName = "testTransactionCreateInlineMatchUrlWithTwoMatches";
+ Bundle request = new Bundle();
+
+ myDaoConfig.setAllowInlineMatchUrlReferences(true);
+
+ Patient p = new Patient();
+ p.addIdentifier().setSystem("urn:system").setValue(methodName);
+ myPatientDao.create(p, mySrd).getId();
+
+ p = new Patient();
+ p.addIdentifier().setSystem("urn:system").setValue(methodName);
+ myPatientDao.create(p, mySrd).getId();
+
+ Observation o = new Observation();
+ o.getCode().setText("Some Observation");
+ o.getSubject().setReference("Patient?identifier=urn%3Asystem%7C" + methodName);
+ request.addEntry().setResource(o).getRequest().setMethod(HTTPVerb.POST);
+
+ try {
+ mySystemDao.transaction(myRequestDetails, request);
+ fail();
+ } catch (InvalidRequestException e) {
+ assertEquals("Invalid match URL \"Patient?identifier=urn%3Asystem%7CtestTransactionCreateInlineMatchUrlWithTwoMatches\" - Multiple resources match this search", e.getMessage());
+ }
+ }
+
@Test
public void testTransactionCreateMatchUrlWithTwoMatch() {
String methodName = "testTransactionCreateMatchUrlWithTwoMatch";
diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/config/TestDstu2Config.java b/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/config/TestDstu2Config.java
index c8b718df305..0cdc9fe7462 100644
--- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/config/TestDstu2Config.java
+++ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/config/TestDstu2Config.java
@@ -50,6 +50,7 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
retVal.setSubscriptionPollDelay(5000);
retVal.setSubscriptionPurgeInactiveAfterMillis(DateUtils.MILLIS_PER_HOUR);
retVal.setAllowMultipleDelete(true);
+ retVal.setAllowInlineMatchUrlReferences(true);
return retVal;
}
diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/config/TestDstu3Config.java b/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/config/TestDstu3Config.java
index 42f20d2d5dc..e1b92db9eda 100644
--- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/config/TestDstu3Config.java
+++ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/config/TestDstu3Config.java
@@ -46,6 +46,7 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
retVal.setSubscriptionPollDelay(5000);
retVal.setSubscriptionPurgeInactiveAfterMillis(DateUtils.MILLIS_PER_HOUR);
retVal.setAllowMultipleDelete(true);
+ retVal.setAllowInlineMatchUrlReferences(true);
return retVal;
}
diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/BinaryClientTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/BinaryClientTest.java
index aee3a682be8..88ebaf5c00f 100644
--- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/BinaryClientTest.java
+++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/BinaryClientTest.java
@@ -1,7 +1,9 @@
package ca.uhn.fhir.rest.client;
-import static org.junit.Assert.*;
-import static org.mockito.Mockito.*;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import java.io.ByteArrayInputStream;
@@ -17,11 +19,9 @@ import org.apache.http.message.BasicStatusLine;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
-import org.mockito.Mockito;
import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.dstu.resource.Binary;
import ca.uhn.fhir.model.dstu.resource.Conformance;
import ca.uhn.fhir.model.dstu.resource.Patient;
@@ -48,7 +48,7 @@ public class BinaryClientTest {
httpClient = mock(HttpClient.class, new ReturnsDeepStubs());
ctx.getRestfulClientFactory().setHttpClient(httpClient);
- ctx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.NEVER);
+ ctx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
}
@@ -59,7 +59,7 @@ public class BinaryClientTest {
when(httpClient.execute(capt.capture())).thenReturn(httpResponse);
when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", "foo/bar"));
- when(httpResponse.getEntity().getContent()).thenReturn(new ByteArrayInputStream(new byte[] {1,2,3,4}));
+ when(httpResponse.getEntity().getContent()).thenReturn(new ByteArrayInputStream(new byte[] { 1, 2, 3, 4 }));
IClient client = ctx.newRestfulClient(IClient.class, "http://foo");
Binary resp = client.read(new IdDt("http://foo/Patient/123"));
@@ -67,24 +67,17 @@ public class BinaryClientTest {
assertEquals(HttpGet.class, capt.getValue().getClass());
HttpGet get = (HttpGet) capt.getValue();
assertEquals("http://foo/Binary/123", get.getURI().toString());
-
+
assertEquals("foo/bar", resp.getContentType());
assertArrayEquals(new byte[] { 1, 2, 3, 4 }, resp.getContent());
}
- public static void main(String[] args) {
-
- IClient c = Mockito.mock(IClient.class, new ReturnsDeepStubs());
-
- }
-
-
@Test
public void testCreate() throws Exception {
Binary res = new Binary();
res.setContent(new byte[] { 1, 2, 3, 4 });
res.setContentType("text/plain");
-
+
ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(httpClient.execute(capt.capture())).thenReturn(httpResponse);
when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
@@ -92,29 +85,23 @@ public class BinaryClientTest {
when(httpResponse.getEntity().getContent()).thenReturn(new ByteArrayInputStream(new byte[] {}));
IClient client = ctx.newRestfulClient(IClient.class, "http://foo");
- MethodOutcome resp = client.create(res);
+ client.create(res);
assertEquals(HttpPost.class, capt.getValue().getClass());
HttpPost post = (HttpPost) capt.getValue();
assertEquals("http://foo/Binary", post.getURI().toString());
-
- assertEquals("text/plain", post.getEntity().getContentType().getValue());
+
+ assertEquals("text/plain", capt.getValue().getFirstHeader("Content-Type").getValue());
assertArrayEquals(new byte[] { 1, 2, 3, 4 }, IOUtils.toByteArray(post.getEntity().getContent()));
}
-
- private String createBundle() {
- return ctx.newXmlParser().encodeBundleToString(new Bundle());
- }
-
-
private interface IClient extends IBasicClient {
- @Read(type=Binary.class)
+ @Read(type = Binary.class)
public Binary read(@IdParam IdDt theBinary);
- @Create(type=Binary.class)
+ @Create(type = Binary.class)
public MethodOutcome create(@ResourceParam Binary theBinary);
}
diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/DynamicSearchTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/DynamicSearchTest.java
index 63d06a264b1..a72e55159d0 100644
--- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/DynamicSearchTest.java
+++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/DynamicSearchTest.java
@@ -173,8 +173,8 @@ public class DynamicSearchTest {
@Override
public List getSearchParameters() {
ArrayList retVal = new ArrayList();
- retVal.add(new RuntimeSearchParam("param1", "This is the first parameter", "Patient.param1", RestSearchParameterTypeEnum.STRING));
- retVal.add(new RuntimeSearchParam("param2", "This is the second parameter", "Patient.param2", RestSearchParameterTypeEnum.DATE));
+ retVal.add(new RuntimeSearchParam("param1", "This is the first parameter", "Patient.param1", RestSearchParameterTypeEnum.STRING, null));
+ retVal.add(new RuntimeSearchParam("param2", "This is the second parameter", "Patient.param2", RestSearchParameterTypeEnum.DATE, null));
return retVal;
}
diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/client/GenericClientDstu2Test.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/client/GenericClientDstu2Test.java
index bdaa8711e0b..fb583c22261 100644
--- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/client/GenericClientDstu2Test.java
+++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/client/GenericClientDstu2Test.java
@@ -143,7 +143,7 @@ public class GenericClientDstu2Test {
client.fetchConformance().ofType(Conformance.class).execute();
assertEquals("http://example.com/fhir/metadata", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals(1, capt.getAllValues().get(idx).getHeaders("Accept").length);
- assertThat(capt.getAllValues().get(idx).getHeaders("Accept")[0].getValue(), containsString(Constants.HEADER_ACCEPT_VALUE_ALL));
+ assertThat(capt.getAllValues().get(idx).getHeaders("Accept")[0].getValue(), containsString(Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON));
idx++;
client.fetchConformance().ofType(Conformance.class).encodedJson().execute();
@@ -192,12 +192,12 @@ public class GenericClientDstu2Test {
assertEquals("FAMILY", resp.getName().get(0).getFamily().get(0).getValue());
assertEquals("http://" + methodName + ".example.com/fhir/metadata", capt.getAllValues().get(0).getURI().toASCIIString());
assertEquals(1, capt.getAllValues().get(0).getHeaders("Accept").length);
- assertThat(capt.getAllValues().get(0).getHeaders("Accept")[0].getValue(), containsString(Constants.HEADER_ACCEPT_VALUE_ALL));
+ assertThat(capt.getAllValues().get(0).getHeaders("Accept")[0].getValue(), containsString(Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON));
assertThat(capt.getAllValues().get(0).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_XML));
assertThat(capt.getAllValues().get(0).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_JSON));
assertEquals("http://" + methodName + ".example.com/fhir/Patient/123", capt.getAllValues().get(1).getURI().toASCIIString());
assertEquals(1, capt.getAllValues().get(1).getHeaders("Accept").length);
- assertThat(capt.getAllValues().get(1).getHeaders("Accept")[0].getValue(), containsString(Constants.HEADER_ACCEPT_VALUE_ALL));
+ assertThat(capt.getAllValues().get(1).getHeaders("Accept")[0].getValue(), containsString(Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON));
assertThat(capt.getAllValues().get(1).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_XML));
assertThat(capt.getAllValues().get(1).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_JSON));
}
diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/client/GenericClientDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/client/GenericClientDstu3Test.java
new file mode 100644
index 00000000000..c7066560f2a
--- /dev/null
+++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/client/GenericClientDstu3Test.java
@@ -0,0 +1,219 @@
+package ca.uhn.fhir.rest.client;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.input.ReaderInputStream;
+import org.apache.http.HttpResponse;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.message.BasicHeader;
+import org.apache.http.message.BasicStatusLine;
+import org.hl7.fhir.dstu3.model.Binary;
+import org.hl7.fhir.dstu3.model.Conformance;
+import org.hl7.fhir.dstu3.model.OperationOutcome;
+import org.hl7.fhir.dstu3.model.Patient;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.parser.IParser;
+import ca.uhn.fhir.rest.server.Constants;
+import ca.uhn.fhir.util.VersionUtil;
+
+public class GenericClientDstu3Test {
+ private static FhirContext ourCtx;
+ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(GenericClientDstu3Test.class);
+ private HttpClient myHttpClient;
+ private HttpResponse myHttpResponse;
+
+ @Before
+ public void before() {
+ myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
+ ourCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
+ ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
+ myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
+ }
+
+ private byte[] extractBodyAsByteArray(ArgumentCaptor capt) throws IOException {
+ byte[] body = IOUtils.toByteArray(((HttpEntityEnclosingRequestBase) capt.getAllValues().get(0)).getEntity().getContent());
+ return body;
+ }
+
+ private String extractBodyAsString(ArgumentCaptor capt) throws IOException {
+ String body = IOUtils.toString(((HttpEntityEnclosingRequestBase) capt.getAllValues().get(0)).getEntity().getContent(), "UTF-8");
+ return body;
+ }
+
+ @Test
+ public void testUserAgentForConformance() throws Exception {
+ IParser p = ourCtx.newXmlParser();
+
+ Conformance conf = new Conformance();
+ conf.setCopyright("COPY");
+
+ final String respString = p.encodeResourceToString(conf);
+ ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class);
+ when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
+ when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
+ when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
+ when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer() {
+ @Override
+ public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
+ return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8"));
+ }
+ });
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
+
+ client.fetchConformance().ofType(Conformance.class).execute();
+ assertEquals("http://example.com/fhir/metadata", capt.getAllValues().get(0).getURI().toASCIIString());
+ validateUserAgent(capt);
+ }
+
+ @Test
+ public void testUserAgentForBinary() throws Exception {
+ IParser p = ourCtx.newXmlParser();
+
+ Conformance conf = new Conformance();
+ conf.setCopyright("COPY");
+
+ final String respString = p.encodeResourceToString(conf);
+ ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class);
+ when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
+ when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
+ when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
+ when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer() {
+ @Override
+ public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
+ return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8"));
+ }
+ });
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
+
+ Binary bin = new Binary();
+ bin.setContentType("application/foo");
+ bin.setContent(new byte[] { 0, 1, 2, 3, 4 });
+ client.create().resource(bin).execute();
+
+ ourLog.info(Arrays.asList(capt.getAllValues().get(0).getAllHeaders()).toString());
+
+ assertEquals("http://example.com/fhir/Binary", capt.getAllValues().get(0).getURI().toASCIIString());
+ validateUserAgent(capt);
+
+ assertEquals("application/foo", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue());
+ assertEquals(Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
+ assertArrayEquals(new byte[] { 0, 1, 2, 3, 4 }, extractBodyAsByteArray(capt));
+
+ }
+
+ @Test
+ public void testBinaryCreateWithNoContentType() throws Exception {
+ IParser p = ourCtx.newXmlParser();
+
+ OperationOutcome conf = new OperationOutcome();
+ conf.getText().setDivAsString("OK!");
+
+ final String respString = p.encodeResourceToString(conf);
+ ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class);
+ when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
+ when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
+ when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
+ when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer() {
+ @Override
+ public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
+ return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8"));
+ }
+ });
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
+
+ Binary bin = new Binary();
+ bin.setContent(new byte[] { 0, 1, 2, 3, 4 });
+ client.create().resource(bin).execute();
+
+ ourLog.info(Arrays.asList(capt.getAllValues().get(0).getAllHeaders()).toString());
+
+ assertEquals("http://example.com/fhir/Binary", capt.getAllValues().get(0).getURI().toASCIIString());
+ validateUserAgent(capt);
+
+ assertEquals("application/xml+fhir;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
+ assertEquals(Constants.CT_FHIR_XML, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
+ assertArrayEquals(new byte[] { 0, 1, 2, 3, 4 }, ourCtx.newXmlParser().parseResource(Binary.class, extractBodyAsString(capt)).getContent());
+
+ }
+
+ @Test
+ public void testBinaryCreateWithFhirContentType() throws Exception {
+ IParser p = ourCtx.newXmlParser();
+
+ OperationOutcome conf = new OperationOutcome();
+ conf.getText().setDivAsString("OK!");
+
+ final String respString = p.encodeResourceToString(conf);
+ ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class);
+ when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
+ when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
+ when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
+ when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer() {
+ @Override
+ public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
+ return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8"));
+ }
+ });
+
+ IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
+
+ Patient pt = new Patient();
+ pt.getText().setDivAsString("A PATIENT");
+
+ Binary bin = new Binary();
+ bin.setContent(ourCtx.newJsonParser().encodeResourceToString(pt).getBytes("UTF-8"));
+ bin.setContentType(Constants.CT_FHIR_JSON);
+ client.create().resource(bin).execute();
+
+ ourLog.info(Arrays.asList(capt.getAllValues().get(0).getAllHeaders()).toString());
+
+ assertEquals("http://example.com/fhir/Binary", capt.getAllValues().get(0).getURI().toASCIIString());
+ validateUserAgent(capt);
+
+ assertEquals("application/xml+fhir;charset=utf-8", capt.getAllValues().get(0).getHeaders("Content-Type")[0].getValue().toLowerCase().replace(" ", ""));
+ assertEquals(Constants.CT_FHIR_XML, capt.getAllValues().get(0).getHeaders("Accept")[0].getValue());
+ Binary output = ourCtx.newXmlParser().parseResource(Binary.class, extractBodyAsString(capt));
+ assertEquals(Constants.CT_FHIR_JSON, output.getContentType());
+
+ Patient outputPt = (Patient) ourCtx.newJsonParser().parseResource(new String(output.getContent(), "UTF-8"));
+ assertEquals("A PATIENT
", outputPt.getText().getDivAsString());
+ }
+
+ private void validateUserAgent(ArgumentCaptor capt) {
+ assertEquals(1, capt.getAllValues().get(0).getHeaders("User-Agent").length);
+ assertEquals(expectedUserAgent(), capt.getAllValues().get(0).getHeaders("User-Agent")[0].getValue());
+ }
+
+ private String expectedUserAgent() {
+ return "HAPI-FHIR/" + VersionUtil.getVersion() + " (FHIR Client)";
+ }
+
+ @BeforeClass
+ public static void beforeClass() {
+ ourCtx = FhirContext.forDstu3();
+ }
+
+}
diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/CreateBinaryDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/CreateBinaryDstu3Test.java
new file mode 100644
index 00000000000..88a39f956a7
--- /dev/null
+++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/CreateBinaryDstu3Test.java
@@ -0,0 +1,161 @@
+package ca.uhn.fhir.rest.server;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.servlet.ServletHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.hl7.fhir.dstu3.model.Binary;
+import org.hl7.fhir.dstu3.model.IdType;
+import org.hl7.fhir.dstu3.model.Patient;
+import org.hl7.fhir.instance.model.api.IBaseResource;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.rest.annotation.Create;
+import ca.uhn.fhir.rest.annotation.ResourceParam;
+import ca.uhn.fhir.rest.api.MethodOutcome;
+import ca.uhn.fhir.util.PortUtil;
+
+public class CreateBinaryDstu3Test {
+ private static CloseableHttpClient ourClient;
+ private static int ourPort;
+ private static FhirContext ourCtx = FhirContext.forDstu3();
+ private static Server ourServer;
+ private static Binary ourLastBinary;
+ private static String ourLastBinaryString;
+ private static byte[] ourLastBinaryBytes;
+
+
+
+ @Before
+ public void before() {
+ ourLastBinary = null;
+ ourLastBinaryBytes = null;
+ ourLastBinaryString = null;
+ }
+
+
+ @Test
+ public void testRawBytesNoContentType() throws Exception {
+ HttpPost post = new HttpPost("http://localhost:" + ourPort + "/Binary");
+ post.setEntity(new ByteArrayEntity(new byte[] {0,1,2,3,4}));
+ ourClient.execute(post);
+
+ assertNull(ourLastBinary.getContentType());
+ assertArrayEquals(new byte[] {0,1,2,3,4}, ourLastBinary.getContent());
+ }
+
+ @Test
+ public void testRawBytesBinaryContentType() throws Exception {
+ HttpPost post = new HttpPost("http://localhost:" + ourPort + "/Binary");
+ post.setEntity(new ByteArrayEntity(new byte[] {0,1,2,3,4}));
+ post.addHeader("Content-Type", "application/foo");
+ ourClient.execute(post);
+
+ assertEquals("application/foo", ourLastBinary.getContentType());
+ assertArrayEquals(new byte[] {0,1,2,3,4}, ourLastBinary.getContent());
+ assertArrayEquals(new byte[] {0,1,2,3,4}, ourLastBinaryBytes);
+ }
+
+ /**
+ * Technically the client shouldn't be doing it this way,
+ * but we'll be accepting
+ */
+ @Test
+ public void testRawBytesFhirContentType() throws Exception {
+
+ Binary b = new Binary();
+ b.setContentType("application/foo");
+ b.setContent(new byte[] {0,1,2,3,4});
+ String encoded = ourCtx.newJsonParser().encodeResourceToString(b);
+
+ HttpPost post = new HttpPost("http://localhost:" + ourPort + "/Binary");
+ post.setEntity(new StringEntity(encoded));
+ post.addHeader("Content-Type", Constants.CT_FHIR_JSON);
+ ourClient.execute(post);
+
+ assertEquals("application/foo", ourLastBinary.getContentType());
+ assertArrayEquals(new byte[] {0,1,2,3,4}, ourLastBinary.getContent());
+ }
+
+ @Test
+ public void testRawBytesFhirContentTypeContainingFhir() throws Exception {
+
+ Patient p = new Patient();
+ p.getText().setDivAsString("A PATIENT");
+
+ Binary b = new Binary();
+ b.setContentType("application/xml+fhir");
+ b.setContent(ourCtx.newXmlParser().encodeResourceToString(p).getBytes("UTF-8"));
+ String encoded = ourCtx.newJsonParser().encodeResourceToString(b);
+
+ HttpPost post = new HttpPost("http://localhost:" + ourPort + "/Binary");
+ post.setEntity(new StringEntity(encoded));
+ post.addHeader("Content-Type", Constants.CT_FHIR_JSON);
+ ourClient.execute(post);
+
+ assertEquals("application/xml+fhir", ourLastBinary.getContentType());
+ assertArrayEquals(b.getContent(), ourLastBinary.getContent());
+ assertEquals(encoded, ourLastBinaryString);
+ assertArrayEquals(encoded.getBytes("UTF-8"), ourLastBinaryBytes);
+ }
+
+ @AfterClass
+ public static void afterClass() throws Exception {
+ ourServer.stop();
+ }
+
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ ourPort = PortUtil.findFreePort();
+ ourServer = new Server(ourPort);
+
+ BinaryProvider binaryProvider = new BinaryProvider();
+
+ ServletHandler proxyHandler = new ServletHandler();
+ RestfulServer servlet = new RestfulServer(ourCtx);
+ servlet.setResourceProviders(binaryProvider);
+ ServletHolder servletHolder = new ServletHolder(servlet);
+ proxyHandler.addServletWithMapping(servletHolder, "/*");
+ ourServer.setHandler(proxyHandler);
+ ourServer.start();
+
+ PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
+ HttpClientBuilder builder = HttpClientBuilder.create();
+ builder.setConnectionManager(connectionManager);
+ ourClient = builder.build();
+ }
+
+ public static class BinaryProvider implements IResourceProvider {
+
+ @Override
+ public Class extends IBaseResource> getResourceType() {
+ return Binary.class;
+ }
+
+ @Create()
+ public MethodOutcome createBinary(@ResourceParam Binary theBinary, @ResourceParam String theBinaryString, @ResourceParam byte[] theBinaryBytes) {
+ ourLastBinary = theBinary;
+ ourLastBinaryString = theBinaryString;
+ ourLastBinaryBytes = theBinaryBytes;
+ return new MethodOutcome(new IdType("Binary/001/_history/002"));
+ }
+
+ }
+
+}
diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/CompartmentGeneratorMojo.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/CompartmentGeneratorMojo.java
deleted file mode 100644
index 843189ae17a..00000000000
--- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/CompartmentGeneratorMojo.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package ca.uhn.fhir.tinder;
-
-import org.apache.maven.plugin.AbstractMojo;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
-import org.apache.maven.plugins.annotations.Parameter;
-
-import ca.uhn.fhir.tinder.parser.CompartmentParser;
-
-public class CompartmentGeneratorMojo extends AbstractMojo {
-
- @Parameter(required = true)
- private String fhirVersion;
-
- @Override
- public void execute() throws MojoExecutionException, MojoFailureException {
- CompartmentParser p = new CompartmentParser(fhirVersion);
- try {
- p.parse();
- } catch (MojoExecutionException e) {
- throw e;
- } catch (MojoFailureException e) {
- throw e;
- } catch (Exception e) {
- throw new MojoFailureException("Failure during parse", e);
- }
- }
-
- public static void main(String[] args) throws MojoExecutionException, MojoFailureException {
- CompartmentGeneratorMojo mojo = new CompartmentGeneratorMojo();
- mojo.fhirVersion = "dstu2";
- mojo.execute();
- }
-
-}
diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderStructuresMojo.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderStructuresMojo.java
index f4d9a368819..890d35745ce 100644
--- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderStructuresMojo.java
+++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderStructuresMojo.java
@@ -228,7 +228,7 @@ public class TinderStructuresMojo extends AbstractMojo {
String dtOutputDir = "target/generated-sources/tinder/ca/uhn/fhir/model/dev/composite";
ResourceGeneratorUsingSpreadsheet rp = new ResourceGeneratorUsingSpreadsheet("dstu2", ".");
- rp.setBaseResourceNames(Arrays.asList( "supplyrequest"
+ rp.setBaseResourceNames(Arrays.asList( "patient", "auditevent" , "observation"
// //, "contract"
// "valueset", "organization", "location"
// , "observation", "conformance"
diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/Resource.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/Resource.java
index 1b53906c08c..3b9e60a3f80 100644
--- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/Resource.java
+++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/Resource.java
@@ -1,5 +1,8 @@
package ca.uhn.fhir.tinder.model;
+import java.util.ArrayList;
+import java.util.List;
+
public class Resource extends BaseRootType {
@Override
@@ -20,4 +23,20 @@ public class Resource extends BaseRootType {
return name;
}
+ public SearchParameter getSearchParameterByName(String theName) {
+ for (SearchParameter next : getSearchParameters()) {
+ if (next.getName().equalsIgnoreCase(theName)) {
+ return next;
+ }
+ }
+ return null;
+ }
+ public List getSearchParameterNames() {
+ ArrayList retVal = new ArrayList();
+ for (SearchParameter next : getSearchParameters()) {
+ retVal.add(next.getName());
+ }
+ return retVal;
+ }
+
}
diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/SearchParameter.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/SearchParameter.java
index b91e2aa668a..201d88dc92b 100644
--- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/SearchParameter.java
+++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/SearchParameter.java
@@ -10,6 +10,7 @@ import org.apache.commons.lang3.StringUtils;
public class SearchParameter {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParameter.class);
+ private List myCompartments = new ArrayList();
private List myCompositeOf;
private List myCompositeTypes;
private String myDescription;
@@ -18,7 +19,6 @@ public class SearchParameter {
private String myResourceName;
private List myTargetTypes;
private String myType;
-
private String myVersion;
public SearchParameter(String theVersion, String theResourceName) {
@@ -26,6 +26,14 @@ public class SearchParameter {
this.myResourceName = theResourceName;
}
+ public void addCompartment(String theCompartment) {
+ myCompartments.add(theCompartment);
+ }
+
+ public List getCompartments() {
+ return myCompartments;
+ }
+
public List getCompositeOf() {
if (myCompositeOf == null) {
myCompositeOf = new ArrayList();
diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/BaseStructureSpreadsheetParser.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/BaseStructureSpreadsheetParser.java
index c13a6afa0ce..14ef3483899 100644
--- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/BaseStructureSpreadsheetParser.java
+++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/BaseStructureSpreadsheetParser.java
@@ -16,6 +16,7 @@ import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.WordUtils;
import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
@@ -404,7 +405,7 @@ public abstract class BaseStructureSpreadsheetParser extends BaseStructureParser
/**
* Subclasses may override
*/
- protected void postProcess(BaseElement theTarget) {
+ protected void postProcess(BaseElement theTarget) throws MojoFailureException {
// nothing
}
diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/CompartmentParser.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/CompartmentParser.java
index 56ee4fe4485..29ce20ae055 100644
--- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/CompartmentParser.java
+++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/CompartmentParser.java
@@ -1,20 +1,31 @@
package ca.uhn.fhir.tinder.parser;
+import static org.apache.commons.lang3.StringUtils.isBlank;
+
import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
import org.apache.maven.plugin.MojoFailureException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import ca.uhn.fhir.tinder.model.BaseElement;
+import ca.uhn.fhir.tinder.model.Resource;
+import ca.uhn.fhir.tinder.model.SearchParameter;
import ca.uhn.fhir.tinder.util.XMLUtils;
public class CompartmentParser {
private String myVersion;
+ private Resource myResourceDef;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CompartmentParser.class);
- public CompartmentParser(String theVersion) {
+ public CompartmentParser(String theVersion, Resource theResourceDef) {
myVersion = theVersion;
+ myResourceDef = theResourceDef;
}
public void parse() throws Exception {
@@ -45,6 +56,67 @@ public class CompartmentParser {
throw new Exception("Failed to find worksheet with name 'Data Elements' in spreadsheet: " + resName);
}
+ Element table = (Element) resourcesSheet.getElementsByTagName("Table").item(0);
+ NodeList rows = table.getElementsByTagName("Row");
+
+ Map col2compartment = new HashMap();
+ Element headerRow = (Element) rows.item(0);
+ for (int i = 1; i < headerRow.getElementsByTagName("Cell").getLength(); i++) {
+ Element cellElement = (Element) headerRow.getElementsByTagName("Cell").item(i);
+ Element dataElement = (Element) cellElement.getElementsByTagName("Data").item(0);
+ col2compartment.put(i, dataElement.getTextContent());
+ }
+
+ Element row = null;
+ for (int i = 1; i < rows.getLength(); i++) {
+ Element nextRow = (Element) rows.item(i);
+
+ NodeList cells = nextRow.getElementsByTagName("Cell");
+ Element cellElement = (Element) cells.item(0);
+ Element dataElement = (Element) cellElement.getElementsByTagName("Data").item(0);
+ if (dataElement.getTextContent().equals(myResourceDef.getName())) {
+ row = nextRow;
+ break;
+ }
+ }
+
+ if (row == null) {
+ ourLog.debug("No compartments for resource {}", myResourceDef.getName());
+ return;
+ }
+
+ NodeList cells = row.getElementsByTagName("Cell");
+ for (int i = 1; i < cells.getLength(); i++) {
+ Element cellElement = (Element) cells.item(i);
+ int index = i;
+ if (cellElement.hasAttribute("Index")) {
+ index = Integer.parseInt(cellElement.getAttribute("Index"));
+ }
+
+ String compartment = col2compartment.get(index);
+
+ Element dataElement = (Element) cellElement.getElementsByTagName("Data").item(0);
+ String namesUnsplit = dataElement.getTextContent();
+ String[] namesSplit = namesUnsplit.split("\\|");
+ for (String nextName : namesSplit) {
+ nextName = nextName.trim();
+ if (isBlank(nextName)) {
+ continue;
+ }
+
+ String[] parts = nextName.split("\\.");
+ if (parts[0].equals("{def}")) {
+ continue;
+ }
+ Resource element = myResourceDef;
+ SearchParameter sp = element.getSearchParameterByName(parts[0]);
+ if (sp == null) {
+ throw new MojoFailureException("Can't find child named " + parts[0] + " - Valid names: " + element.getSearchParameterNames());
+ }
+
+ sp.addCompartment(compartment);
+ }
+ }
}
}
diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/DatatypeGeneratorUsingSpreadsheet.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/DatatypeGeneratorUsingSpreadsheet.java
index b219761afa9..8045985edd5 100644
--- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/DatatypeGeneratorUsingSpreadsheet.java
+++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/DatatypeGeneratorUsingSpreadsheet.java
@@ -22,7 +22,7 @@ import com.google.common.reflect.ClassPath.ClassInfo;
public class DatatypeGeneratorUsingSpreadsheet extends BaseStructureSpreadsheetParser {
@Override
- protected void postProcess(BaseElement theTarget) {
+ protected void postProcess(BaseElement theTarget) throws MojoFailureException {
super.postProcess(theTarget);
/*
diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/ResourceGeneratorUsingSpreadsheet.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/ResourceGeneratorUsingSpreadsheet.java
index 44cf091d25b..9ed90614419 100644
--- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/ResourceGeneratorUsingSpreadsheet.java
+++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/ResourceGeneratorUsingSpreadsheet.java
@@ -26,12 +26,21 @@ public class ResourceGeneratorUsingSpreadsheet extends BaseStructureSpreadsheetP
}
@Override
- protected void postProcess(BaseElement theTarget) {
+ protected void postProcess(BaseElement theTarget) throws MojoFailureException {
super.postProcess(theTarget);
if ("Bundle".equals(theTarget.getName())) {
addEverythingToSummary(theTarget);
}
+
+ if (getVersion().equals("dstu2") && theTarget instanceof Resource) {
+ try {
+ new CompartmentParser(getVersion(), (Resource) theTarget).parse();
+ } catch (Exception e) {
+ throw new MojoFailureException(e.toString(), e);
+ }
+ }
+
}
private void addEverythingToSummary(BaseElement theTarget) {
diff --git a/hapi-tinder-plugin/src/main/resources/vm/resource.vm b/hapi-tinder-plugin/src/main/resources/vm/resource.vm
index 9ac7c4e85d1..b83f5519c4d 100644
--- a/hapi-tinder-plugin/src/main/resources/vm/resource.vm
+++ b/hapi-tinder-plugin/src/main/resources/vm/resource.vm
@@ -56,6 +56,13 @@ public class ${className} extends ca.uhn.fhir.model.${version}.resource.BaseReso
*
*/
@SearchParamDefinition(name="${param.name}", path="${param.path}", description="${param.description}", type="${param.type}" #{if}($param.compositeOf.empty == false) , compositeOf={ #{foreach}($compositeOf in $param.compositeOf) "${compositeOf}"#{if}($foreach.hasNext), #{end}#{end} } #{end} )
+#if ($param.compartments.size() > 0)
+ @Compartments(providesMembershipIn={
+#foreach ($compartment in $param.compartments)
+ @Compartment(name="$compartment") #{if}($foreach.hasNext), #{end}
+#end
+ })
+#end
public static final String $param.constantName = "${param.name}";
/**
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 6509a2d9d09..b3fea478314 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -59,6 +59,50 @@
JPA server now supports :above and :below qualifiers on URI search params
+
+ Add optional support (disabled by default for now) to JPA server to support
+ inline references containing search URLs. These URLs will be resolved when
+ a resource is being created/updated and replaced with the single matching
+ resource. This is being used as a part of the May 2016 Connectathon for
+ a testing scenario.
+
+
+ The server no longer adds a
+ WWW-Authenticate]]>
+ header to the response if any resource provider code throws an
+ AuthenticationException]]>. This header is
+ used for interactive authentication, which isn't generally
+ appropriate for FHIR. We added code to add this header a long time
+ ago for testing purposes and it never got removed. Please let us
+ know if you need the ability to add this header automatically. Thanks
+ to Lars Kristian Roland for pointing this out.
+
+
+ In the client, the create/update operations on a Binary resource
+ (which use the raw binary's content type as opposed to the FHIR
+ content type) were not including any request headers (Content-Type,
+ User-Agent, etc.) Thanks to Peter Van Houte of Agfa Healthcare for
+ reporting!
+
+
+ Handling of Binary resources containing embedded FHIR resources for
+ create/update/etc operations has been corrected per the FHIR rules
+ outlined at
+ Binary Resource in both
+ the client and server.
+ ]]>
+ Essentially, if the Binary contains something
+ that isn't FHIR (e.g. an image with an image content-type) the
+ client will send the raw data with the image content type to the server. The
+ server will place the content type and raw data into a Binary resource instance
+ and pass those to the resource provider. This part was already correct previous
+ to 1.5.
+ ]]>
+ On the other hand, if the Binary contains a FHIR content type, the Binary
+ is now sent by the client to the server as a Binary resource with a FHIR content-type,
+ and the embedded FHIR content is contained in the appropriate fields. The server
+ will pass this "outer" Binary resource to the resource provider code.
+
The RequestDetails and ActionRequestDetails objects which are passed to
server interceptor methods and may also be used as server provider method
diff --git a/src/site/xdoc/doc_rest_operations.xml b/src/site/xdoc/doc_rest_operations.xml
index 80b02082698..97f7b0c424d 100644
--- a/src/site/xdoc/doc_rest_operations.xml
+++ b/src/site/xdoc/doc_rest_operations.xml
@@ -115,8 +115,9 @@
Update methods must be annotated with the
@Update
annotation, and have a parameter annotated with the
- @Resource
+ @ResourceParam
annotation. This parameter contains the resource instance to be created.
+ See the @ResourceParam for information on the types allowed for this parameter (resource types, String, byte[]).
In addition, the method may optionally have a parameter annotated with the
@@ -316,8 +317,9 @@
Create methods must be annotated with the
@Create
annotation, and have a single parameter annotated with the
- @Resource
+ @ResourceParam
annotation. This parameter contains the resource instance to be created.
+ See the @ResourceParam for information on the types allowed for this parameter (resource types, String, byte[]).
Create methods must return an object of type
@@ -1104,7 +1106,7 @@
Validate methods must be annotated with the
@Validate
annotation, and have a parameter annotated with the
- @Resource
+ @ResourceParam
annotation. This parameter contains the resource instance to be created.