Merge branch 'master' into jaxrs-client

This commit is contained in:
jamesagnew 2016-02-27 09:48:36 -05:00
commit 69450c7dab
44 changed files with 1686 additions and 794 deletions

View File

@ -70,6 +70,8 @@ import ca.uhn.fhir.model.api.IResourceBlock;
import ca.uhn.fhir.model.api.IValueSetEnumBinder; import ca.uhn.fhir.model.api.IValueSetEnumBinder;
import ca.uhn.fhir.model.api.annotation.Block; import ca.uhn.fhir.model.api.annotation.Block;
import ca.uhn.fhir.model.api.annotation.Child; 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.DatatypeDef;
import ca.uhn.fhir.model.api.annotation.Description; import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.Extension; import ca.uhn.fhir.model.api.annotation.Extension;
@ -87,7 +89,6 @@ import ca.uhn.fhir.util.ReflectionUtil;
class ModelScanner { class ModelScanner {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ModelScanner.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ModelScanner.class);
private final Map<Class<? extends Annotation>, Class<? extends Annotation>> myAnnotationForwards = new HashMap<Class<? extends Annotation>, Class<? extends Annotation>>();
private Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> myClassToElementDefinitions = new HashMap<Class<? extends IBase>, BaseRuntimeElementDefinition<?>>(); private Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> myClassToElementDefinitions = new HashMap<Class<? extends IBase>, BaseRuntimeElementDefinition<?>>();
private FhirContext myContext; private FhirContext myContext;
private Map<String, RuntimeResourceDefinition> myIdToResourceDefinition = new HashMap<String, RuntimeResourceDefinition>(); private Map<String, RuntimeResourceDefinition> myIdToResourceDefinition = new HashMap<String, RuntimeResourceDefinition>();
@ -101,7 +102,8 @@ class ModelScanner {
private Set<Class<? extends IBase>> myVersionTypes; private Set<Class<? extends IBase>> myVersionTypes;
ModelScanner(FhirContext theContext, FhirVersionEnum theVersion, Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theExistingDefinitions, Collection<Class<? extends IElement>> theResourceTypes) throws ConfigurationException { ModelScanner(FhirContext theContext, FhirVersionEnum theVersion, Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theExistingDefinitions,
Collection<Class<? extends IElement>> theResourceTypes) throws ConfigurationException {
myContext = theContext; myContext = theContext;
myVersion = theVersion; myVersion = theVersion;
Set<Class<? extends IBase>> toScan; Set<Class<? extends IBase>> toScan;
@ -233,68 +235,13 @@ class ModelScanner {
} }
/** /**
* There are two implementations of all of the annotations (e.g. {@link Child} and * 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
* {@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
* ones. Annotations can't extend each other or implement interfaces or anything like that, so rather than duplicate * Proxy to simulate the HAPI annotations if the HL7.org ones are found instead.
* 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 extends Annotation> T pullAnnotation(AnnotatedElement theTarget, Class<T> theAnnotationType) {
private <T extends Annotation> T pullAnnotation(Class<?> theContainer, AnnotatedElement theTarget, Class<T> theAnnotationType) {
T retVal = theTarget.getAnnotation(theAnnotationType); T retVal = theTarget.getAnnotation(theAnnotationType);
// if (myContext.getVersion().getVersion() != FhirVersionEnum.DSTU2_HL7ORG) { return retVal;
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;
} }
private void scan(Class<? extends IBase> theClass) throws ConfigurationException { private void scan(Class<? extends IBase> theClass) throws ConfigurationException {
@ -303,17 +250,18 @@ class ModelScanner {
return; return;
} }
ResourceDef resourceDefinition = pullAnnotation(theClass, theClass, ResourceDef.class); ResourceDef resourceDefinition = pullAnnotation(theClass, ResourceDef.class);
if (resourceDefinition != null) { if (resourceDefinition != null) {
if (!IBaseResource.class.isAssignableFrom(theClass)) { 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") @SuppressWarnings("unchecked")
Class<? extends IBaseResource> resClass = (Class<? extends IBaseResource>) theClass; Class<? extends IBaseResource> resClass = (Class<? extends IBaseResource>) theClass;
scanResource(resClass, resourceDefinition); scanResource(resClass, resourceDefinition);
} }
DatatypeDef datatypeDefinition = pullAnnotation(theClass, theClass, DatatypeDef.class); DatatypeDef datatypeDefinition = pullAnnotation(theClass, DatatypeDef.class);
if (datatypeDefinition != null) { if (datatypeDefinition != null) {
if (ICompositeType.class.isAssignableFrom(theClass)) { if (ICompositeType.class.isAssignableFrom(theClass)) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -325,17 +273,19 @@ class ModelScanner {
scanPrimitiveDatatype(resClass, datatypeDefinition); scanPrimitiveDatatype(resClass, datatypeDefinition);
} else { } else {
return; 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 (blockDefinition != null) {
if (IResourceBlock.class.isAssignableFrom(theClass) || IBaseBackboneElement.class.isAssignableFrom(theClass) || IBaseDatatypeElement.class.isAssignableFrom(theClass)) { if (IResourceBlock.class.isAssignableFrom(theClass) || IBaseBackboneElement.class.isAssignableFrom(theClass) || IBaseDatatypeElement.class.isAssignableFrom(theClass)) {
scanBlock(theClass); scanBlock(theClass);
} else { } 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; RuntimeCompositeDatatypeDefinition resourceDef;
if (theClass.equals(ExtensionDt.class)) { if (theClass.equals(ExtensionDt.class)) {
resourceDef = new RuntimeExtensionDtDefinition(theDatatypeDefinition, theClass, true); resourceDef = new RuntimeExtensionDtDefinition(theDatatypeDefinition, theClass, true);
// } else if (IBaseMetaType.class.isAssignableFrom(theClass)) { // } else if (IBaseMetaType.class.isAssignableFrom(theClass)) {
// resourceDef = new RuntimeMetaDefinition(theDatatypeDefinition, theClass, isStandardType(theClass)); // resourceDef = new RuntimeMetaDefinition(theDatatypeDefinition, theClass, isStandardType(theClass));
} else { } else {
resourceDef = new RuntimeCompositeDatatypeDefinition(theDatatypeDefinition, theClass, isStandardType(theClass)); resourceDef = new RuntimeCompositeDatatypeDefinition(theDatatypeDefinition, theClass, isStandardType(theClass));
} }
@ -429,7 +379,8 @@ class ModelScanner {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void scanCompositeElementForChildren(Class<? extends IBase> theClass, Set<String> elementNames, TreeMap<Integer, BaseRuntimeDeclaredChildDefinition> theOrderToElementDef, TreeMap<Integer, BaseRuntimeDeclaredChildDefinition> theOrderToExtensionDef) { private void scanCompositeElementForChildren(Class<? extends IBase> theClass, Set<String> elementNames, TreeMap<Integer, BaseRuntimeDeclaredChildDefinition> theOrderToElementDef,
TreeMap<Integer, BaseRuntimeDeclaredChildDefinition> theOrderToExtensionDef) {
int baseElementOrder = theOrderToElementDef.isEmpty() ? 0 : theOrderToElementDef.lastEntry().getKey() + 1; int baseElementOrder = theOrderToElementDef.isEmpty() ? 0 : theOrderToElementDef.lastEntry().getKey() + 1;
for (Field next : theClass.getDeclaredFields()) { for (Field next : theClass.getDeclaredFields()) {
@ -439,16 +390,16 @@ class ModelScanner {
continue; continue;
} }
Child childAnnotation = pullAnnotation(theClass, next, Child.class); Child childAnnotation = pullAnnotation(next, Child.class);
if (childAnnotation == null) { if (childAnnotation == null) {
ourLog.trace("Ignoring non @Child field {} on target type {}", next.getName(), theClass); ourLog.trace("Ignoring non @Child field {} on target type {}", next.getName(), theClass);
continue; continue;
} }
Description descriptionAnnotation = pullAnnotation(theClass, next, Description.class); Description descriptionAnnotation = pullAnnotation(next, Description.class);
TreeMap<Integer, BaseRuntimeDeclaredChildDefinition> orderMap = theOrderToElementDef; TreeMap<Integer, BaseRuntimeDeclaredChildDefinition> orderMap = theOrderToElementDef;
Extension extensionAttr = pullAnnotation(theClass, next, Extension.class); Extension extensionAttr = pullAnnotation(next, Extension.class);
if (extensionAttr != null) { if (extensionAttr != null) {
orderMap = theOrderToExtensionDef; orderMap = theOrderToExtensionDef;
} }
@ -471,8 +422,8 @@ class ModelScanner {
} }
} }
if (order == Child.REPLACE_PARENT) { 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 " throw new ConfigurationException("Field " + next.getName() + "' on target type " + theClass.getSimpleName() + " has order() of REPLACE_PARENT (" + Child.REPLACE_PARENT
+ next.getDeclaringClass().getSimpleName()); + ") but no parent element with extension URL " + extensionAttr.url() + " could be found on type " + next.getDeclaringClass().getSimpleName());
} }
} else { } else {
@ -487,8 +438,8 @@ class ModelScanner {
} }
} }
if (order == Child.REPLACE_PARENT) { 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 " throw new ConfigurationException("Field " + next.getName() + "' on target type " + theClass.getSimpleName() + " has order() of REPLACE_PARENT (" + Child.REPLACE_PARENT
+ next.getDeclaringClass().getSimpleName()); + ") 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(); // 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 * 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
* IDs and can be figured out later
*/ */
if (order == Child.ORDER_UNKNOWN) { if (order == Child.ORDER_UNKNOWN) {
order = Integer.MIN_VALUE; order = Integer.MIN_VALUE;
@ -572,7 +522,8 @@ class ModelScanner {
binder = getBoundCodeBinder(next); 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)) { if (IBaseEnumeration.class.isAssignableFrom(nextElementType)) {
def.setEnumerationType(ReflectionUtil.getGenericCollectionTypeOfFieldWithSecondOrderForList(next)); def.setEnumerationType(ReflectionUtil.getGenericCollectionTypeOfFieldWithSecondOrderForList(next));
@ -600,10 +551,10 @@ class ModelScanner {
RuntimeChildResourceDefinition def = new RuntimeChildResourceDefinition(next, elementName, childAnnotation, descriptionAnnotation, refTypesList); RuntimeChildResourceDefinition def = new RuntimeChildResourceDefinition(next, elementName, childAnnotation, descriptionAnnotation, refTypesList);
orderMap.put(order, def); 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 * Child is a resource block (i.e. a sub-tag within a resource) TODO: do these have a better name according to HL7?
* according to HL7?
*/ */
Class<? extends IBase> blockDef = (Class<? extends IBase>) nextElementType; Class<? extends IBase> blockDef = (Class<? extends IBase>) nextElementType;
@ -611,13 +562,14 @@ class ModelScanner {
RuntimeChildResourceBlockDefinition def = new RuntimeChildResourceBlockDefinition(next, childAnnotation, descriptionAnnotation, elementName, blockDef); RuntimeChildResourceBlockDefinition def = new RuntimeChildResourceBlockDefinition(next, childAnnotation, descriptionAnnotation, elementName, blockDef);
orderMap.put(order, def); 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); RuntimeChildAny def = new RuntimeChildAny(next, elementName, childAnnotation, descriptionAnnotation);
orderMap.put(order, def); orderMap.put(order, def);
} else if (IDatatype.class.isAssignableFrom(nextElementType) || IPrimitiveType.class.isAssignableFrom(nextElementType) || ICompositeType.class.isAssignableFrom(nextElementType) || IBaseDatatype.class.isAssignableFrom(nextElementType) } else if (IDatatype.class.isAssignableFrom(nextElementType) || IPrimitiveType.class.isAssignableFrom(nextElementType) || ICompositeType.class.isAssignableFrom(nextElementType)
|| IBaseExtension.class.isAssignableFrom(nextElementType)) { || IBaseDatatype.class.isAssignableFrom(nextElementType) || IBaseExtension.class.isAssignableFrom(nextElementType)) {
Class<? extends IBase> nextDatatype = (Class<? extends IBase>) nextElementType; Class<? extends IBase> nextDatatype = (Class<? extends IBase>) nextElementType;
addScanAlso(nextDatatype); 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 (concept != null) {
if (!ICodedDatatype.class.isAssignableFrom(nextDatatype)) { 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 { } else {
Class<? extends ICodeEnum> type = concept.type(); Class<? extends ICodeEnum> type = concept.type();
myScanAlsoCodeTable.add(type); myScanAlsoCodeTable.add(type);
@ -711,21 +664,23 @@ class ModelScanner {
Class<?> parent = theClass.getSuperclass(); Class<?> parent = theClass.getSuperclass();
primaryNameProvider = false; primaryNameProvider = false;
while (parent.equals(Object.class) == false && isBlank(resourceName)) { while (parent.equals(Object.class) == false && isBlank(resourceName)) {
ResourceDef nextDef = pullAnnotation(theClass, parent, ResourceDef.class); ResourceDef nextDef = pullAnnotation(parent, ResourceDef.class);
if (nextDef != null) { if (nextDef != null) {
resourceName = nextDef.name(); resourceName = nextDef.name();
} }
parent = parent.getSuperclass(); parent = parent.getSuperclass();
} }
if (isBlank(resourceName)) { 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(); String resourceId = resourceDefinition.id();
if (!isBlank(resourceId)) { if (!isBlank(resourceId)) {
if (myIdToResourceDefinition.containsKey(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<Field, SearchParamDefinition> compositeFields = new LinkedHashMap<Field, SearchParamDefinition>(); Map<Field, SearchParamDefinition> compositeFields = new LinkedHashMap<Field, SearchParamDefinition>();
for (Field nextField : theClass.getFields()) { for (Field nextField : theClass.getFields()) {
SearchParamDefinition searchParam = pullAnnotation(theClass, nextField, SearchParamDefinition.class); SearchParamDefinition searchParam = pullAnnotation(nextField, SearchParamDefinition.class);
if (searchParam != null) { if (searchParam != null) {
RestSearchParameterTypeEnum paramType = RestSearchParameterTypeEnum.valueOf(searchParam.type().toUpperCase()); RestSearchParameterTypeEnum paramType = RestSearchParameterTypeEnum.valueOf(searchParam.type().toUpperCase());
if (paramType == null) { if (paramType == null) {
@ -761,7 +716,17 @@ class ModelScanner {
compositeFields.put(nextField, searchParam); compositeFields.put(nextField, searchParam);
continue; continue;
} }
RuntimeSearchParam param = new RuntimeSearchParam(searchParam.name(), searchParam.description(), searchParam.path(), paramType);
Set<String> providesMembershipInCompartments = null;
Compartments compartmentsAnnotation = pullAnnotation(nextField, Compartments.class);
if (compartmentsAnnotation != null) {
providesMembershipInCompartments = new HashSet<String>();
for (Compartment next : compartmentsAnnotation.providesMembershipIn()) {
providesMembershipInCompartments.add(next.name());
}
}
RuntimeSearchParam param = new RuntimeSearchParam(searchParam.name(), searchParam.description(), searchParam.path(), paramType, providesMembershipInCompartments);
theResourceDef.addSearchParam(param); theResourceDef.addSearchParam(param);
nameToParam.put(param.getName(), param); nameToParam.put(param.getName(), param);
} }
@ -774,13 +739,14 @@ class ModelScanner {
for (String nextName : searchParam.compositeOf()) { for (String nextName : searchParam.compositeOf()) {
RuntimeSearchParam param = nameToParam.get(nextName); RuntimeSearchParam param = nameToParam.get(nextName);
if (param == null) { 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; continue;
} }
compositeOf.add(param); 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); theResourceDef.addSearchParam(param);
} }
} }

View File

@ -3,6 +3,7 @@ package ca.uhn.fhir.context;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum; import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
@ -29,23 +30,30 @@ import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
public class RuntimeSearchParam { public class RuntimeSearchParam {
private List<RuntimeSearchParam> myCompositeOf;
private String myDescription; private String myDescription;
private String myName; private String myName;
private RestSearchParameterTypeEnum myParamType; private RestSearchParameterTypeEnum myParamType;
private String myPath; private String myPath;
private List<RuntimeSearchParam> myCompositeOf; private Set<String> myProvidesMembershipInCompartments;
public RuntimeSearchParam(String theName, String theDescription, String thePath, RestSearchParameterTypeEnum theParamType) { public RuntimeSearchParam(String theName, String theDescription, String thePath, RestSearchParameterTypeEnum theParamType, List<RuntimeSearchParam> theCompositeOf,
this(theName, theDescription, thePath, theParamType, null); Set<String> theProvidesMembershipInCompartments) {
}
public RuntimeSearchParam(String theName, String theDescription, String thePath, RestSearchParameterTypeEnum theParamType, List<RuntimeSearchParam> theCompositeOf) {
super(); super();
myName = theName; myName = theName;
myDescription = theDescription; myDescription = theDescription;
myPath = thePath; myPath = thePath;
myParamType = theParamType; myParamType = theParamType;
myCompositeOf = theCompositeOf; 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<String> theProvidesMembershipInCompartments) {
this(theName, theDescription, thePath, theParamType, null, theProvidesMembershipInCompartments);
} }
public List<RuntimeSearchParam> getCompositeOf() { public List<RuntimeSearchParam> getCompositeOf() {
@ -70,7 +78,7 @@ public class RuntimeSearchParam {
public List<String> getPathsSplit() { public List<String> getPathsSplit() {
String path = getPath(); String path = getPath();
if (path.indexOf('|')==-1) { if (path.indexOf('|') == -1) {
return Collections.singletonList(path); return Collections.singletonList(path);
} }
@ -83,4 +91,11 @@ public class RuntimeSearchParam {
return retVal; return retVal;
} }
/**
* Can return null
*/
public Set<String> getProvidesMembershipInCompartments() {
return myProvidesMembershipInCompartments;
}
} }

View File

@ -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 <code>Patient</code> on
* the <code>Observation.subject</code> field.
*/
String name();
}

View File

@ -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();
}

View File

@ -25,6 +25,29 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; 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.
* <p>
* For example, in a {@link Create} operation the method parameter annotated with this
* annotation will contain the actual resource being created.
* </p>
* <p>
* 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.
* </p>
* <p>
* Note that in servers it is also acceptable to have parameters with this annotation
* which are of type {@link String} or of type <code>byte[]</code>. 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.
* </p>
*/
@Target(value=ElementType.PARAMETER) @Target(value=ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface ResourceParam { public @interface ResourceParam {

View File

@ -1,5 +1,8 @@
package ca.uhn.fhir.rest.method; package ca.uhn.fhir.rest.method;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
/* /*
* #%L * #%L
* HAPI FHIR - Core Library * HAPI FHIR - Core Library
@ -46,6 +49,7 @@ import ca.uhn.fhir.rest.server.IVersionSpecificBundleFactory;
* @author Doug Martin (Regenstrief Center for Biomedical Informatics) * @author Doug Martin (Regenstrief Center for Biomedical Informatics)
*/ */
abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvocation { abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvocation {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHttpClientInvocationWithContents.class);
private final Bundle myBundle; private final Bundle myBundle;
private final BundleTypeEnum myBundleType; private final BundleTypeEnum myBundleType;

View File

@ -117,7 +117,7 @@ abstract class BaseOutcomeReturningMethodBindingWithResourceParam extends BaseOu
@Override @Override
public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException { public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
IResource resource = (IResource) theArgs[myResourceParameterIndex]; IResource resource = (IResource) theArgs[myResourceParameterIndex]; // TODO: use IBaseResource
if (resource == null) { if (resource == null) {
throw new NullPointerException("Resource can not be null"); throw new NullPointerException("Resource can not be null");
} }

View File

@ -451,10 +451,20 @@ public class MethodUtil {
mode = Mode.RESOURCE; mode = Mode.RESOURCE;
} else if (String.class.equals(parameterType)) { } else if (String.class.equals(parameterType)) {
mode = ResourceParameter.Mode.BODY; mode = ResourceParameter.Mode.BODY;
} else if (byte[].class.equals(parameterType)) {
mode = ResourceParameter.Mode.BODY_BYTE_ARRAY;
} else if (EncodingEnum.class.equals(parameterType)) { } else if (EncodingEnum.class.equals(parameterType)) {
mode = Mode.ENCODING; mode = Mode.ENCODING;
} else { } 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); param = new ResourceParameter((Class<? extends IResource>) parameterType, theProvider, mode);
} else if (nextAnnotation instanceof IdParam || nextAnnotation instanceof VersionIdParam) { } else if (nextAnnotation instanceof IdParam || nextAnnotation instanceof VersionIdParam) {

View File

@ -105,8 +105,10 @@ public class ResourceParameter implements IParameter {
return IOUtils.toString(createRequestReader(theRequest)); return IOUtils.toString(createRequestReader(theRequest));
} catch (IOException e) { } catch (IOException e) {
// Shouldn't happen since we're reading from a byte array // 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: case ENCODING:
return RestfulServerUtils.determineRequestEncoding(theRequest); return RestfulServerUtils.determineRequestEncoding(theRequest);
case RESOURCE: case RESOURCE:
@ -201,23 +203,27 @@ public class ResourceParameter implements IParameter {
} }
public static IBaseResource parseResourceFromRequest(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding, Class<? extends IBaseResource> theResourceType) { public static IBaseResource parseResourceFromRequest(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding, Class<? extends IBaseResource> theResourceType) {
IBaseResource retVal; IBaseResource retVal = null;
if (IBaseBinary.class.isAssignableFrom(theResourceType)) { if (IBaseBinary.class.isAssignableFrom(theResourceType)) {
FhirContext ctx = theRequest.getServer().getFhirContext();
String ct = theRequest.getHeader(Constants.HEADER_CONTENT_TYPE); 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(); IBaseBinary binary = (IBaseBinary) ctx.getResourceDefinition("Binary").newInstance();
binary.setContentType(ct); binary.setContentType(ct);
binary.setContent(theRequest.loadRequestContents()); binary.setContent(theRequest.loadRequestContents());
retVal = binary; retVal = binary;
} else { }
}
if (retVal == null) {
retVal = loadResourceFromRequest(theRequest, theMethodBinding, theResourceType); retVal = loadResourceFromRequest(theRequest, theMethodBinding, theResourceType);
} }
return retVal; return retVal;
} }
public enum Mode { public enum Mode {
BODY, ENCODING, RESOURCE BODY, BODY_BYTE_ARRAY, ENCODING, RESOURCE
} }
} }

View File

@ -54,7 +54,7 @@ public class Constants {
public static final String FORMAT_XML = "xml"; public static final String FORMAT_XML = "xml";
public static final String HEADER_ACCEPT = "Accept"; public static final String HEADER_ACCEPT = "Accept";
public static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding"; 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_ALLOW = "Allow";
public static final String HEADER_AUTHORIZATION = "Authorization"; public static final String HEADER_AUTHORIZATION = "Authorization";
public static final String HEADER_AUTHORIZATION_VALPREFIX_BASIC = "Basic "; public static final String HEADER_AUTHORIZATION_VALPREFIX_BASIC = "Basic ";

View File

@ -44,6 +44,7 @@ public enum EncodingEnum {
; ;
private static HashMap<String, EncodingEnum> ourContentTypeToEncoding; private static HashMap<String, EncodingEnum> ourContentTypeToEncoding;
private static HashMap<String, EncodingEnum> ourContentTypeToEncodingStrict;
static { static {
ourContentTypeToEncoding = new HashMap<String, EncodingEnum>(); ourContentTypeToEncoding = new HashMap<String, EncodingEnum>();
@ -52,6 +53,9 @@ public enum EncodingEnum {
ourContentTypeToEncoding.put(next.getResourceContentType(), next); ourContentTypeToEncoding.put(next.getResourceContentType(), next);
} }
// Add before we add the lenient ones
ourContentTypeToEncodingStrict = new HashMap<String, EncodingEnum>(ourContentTypeToEncoding);
/* /*
* These are wrong, but we add them just to be tolerant of other * These are wrong, but we add them just to be tolerant of other
* people's mistakes * people's mistakes
@ -88,10 +92,30 @@ public enum EncodingEnum {
return myResourceContentType; return myResourceContentType;
} }
/**
* Returns the encoding for a given content type, or <code>null</code> if no encoding
* is found.
* <p>
* <b>This method is lenient!</b> Things like "application/xml" will return {@link EncodingEnum#XML}
* even if the "+fhir" part is missing from the expected content type.
* </p>
*/
public static EncodingEnum forContentType(String theContentType) { public static EncodingEnum forContentType(String theContentType) {
return ourContentTypeToEncoding.get(theContentType); return ourContentTypeToEncoding.get(theContentType);
} }
/**
* Returns the encoding for a given content type, or <code>null</code> if no encoding
* is found.
* <p>
* <b>This method is NOT lenient!</b> Things like "application/xml" will return <code>null</code>
* </p>
* @see #forContentType(String)
*/
public static EncodingEnum forContentTypeStrict(String theContentType) {
return ourContentTypeToEncodingStrict.get(theContentType);
}
public String getFormatContentType() { public String getFormatContentType() {
return myFormatContentType; return myFormatContentType;
} }

View File

@ -517,7 +517,6 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
protected void handleRequest(RequestTypeEnum theRequestType, HttpServletRequest theRequest, HttpServletResponse theResponse) throws ServletException, IOException { protected void handleRequest(RequestTypeEnum theRequestType, HttpServletRequest theRequest, HttpServletResponse theResponse) throws ServletException, IOException {
String fhirServerBase = null; String fhirServerBase = null;
boolean requestIsBrowser = requestIsBrowser(theRequest);
ServletRequestDetails requestDetails = new ServletRequestDetails(); ServletRequestDetails requestDetails = new ServletRequestDetails();
requestDetails.setServer(this); requestDetails.setServer(this);
requestDetails.setRequestType(theRequestType); requestDetails.setRequestType(theRequestType);
@ -651,10 +650,6 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
} }
} }
if (requestIsBrowser) {
// if request is coming from a browser, prompt the user to enter login credentials
theResponse.setHeader("WWW-Authenticate", "BASIC realm=\"FHIR\"");
}
writeExceptionToResponse(theResponse, e); writeExceptionToResponse(theResponse, e);
} catch (Throwable e) { } catch (Throwable e) {
@ -1399,9 +1394,4 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
return nextString.length() > 0 && (nextString.charAt(0) == '_' || nextString.charAt(0) == '$' || nextString.equals(Constants.URL_TOKEN_METADATA)); return nextString.length() > 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");
}
} }

View File

@ -43,6 +43,9 @@ ca.uhn.fhir.validation.ValidationResult.noIssuesDetected=No issues detected duri
# JPA Messages # 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.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.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.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} ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.transactionOperationFailedUnknownId=Failed to {0} resource in transaction because no resource could be found with ID {1}

View File

@ -34,32 +34,39 @@ import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
public class DaoConfig { public class DaoConfig {
// ***
// update setter javadoc if default changes
// ***
private boolean myAllowInlineMatchUrlReferences = false;
private boolean myAllowMultipleDelete; private boolean myAllowMultipleDelete;
private int myHardSearchLimit = 1000; private int myHardSearchLimit = 1000;
private int myHardTagListLimit = 1000; private int myHardTagListLimit = 1000;
private int myIncludeLimit = 2000; private int myIncludeLimit = 2000;
// ***
// update setter javadoc if default changes
// ***
private boolean myIndexContainedResources = true;
private List<IServerInterceptor> myInterceptors; private List<IServerInterceptor> myInterceptors;
private ResourceEncodingEnum myResourceEncoding = ResourceEncodingEnum.JSONC; private ResourceEncodingEnum myResourceEncoding = ResourceEncodingEnum.JSONC;
private boolean mySchedulingDisabled; private boolean mySchedulingDisabled;
private boolean mySubscriptionEnabled; private boolean mySubscriptionEnabled;
private long mySubscriptionPollDelay = 1000; private long mySubscriptionPollDelay = 1000;
private Long mySubscriptionPurgeInactiveAfterMillis; private Long mySubscriptionPurgeInactiveAfterMillis;
/** /**
* See {@link #setIncludeLimit(int)} * See {@link #setIncludeLimit(int)}
*/ */
public int getHardSearchLimit() { public int getHardSearchLimit() {
return myHardSearchLimit; return myHardSearchLimit;
} }
public int getHardTagListLimit() { public int getHardTagListLimit() {
return myHardTagListLimit; return myHardTagListLimit;
} }
public int getIncludeLimit() { public int getIncludeLimit() {
return myIncludeLimit; return myIncludeLimit;
} }
/** /**
* Returns the interceptors which will be notified of operations. * Returns the interceptors which will be notified of operations.
* *
@ -84,10 +91,25 @@ public class DaoConfig {
return mySubscriptionPurgeInactiveAfterMillis; return mySubscriptionPurgeInactiveAfterMillis;
} }
/**
* @see #setAllowInlineMatchUrlReferences(boolean)
*/
public boolean isAllowInlineMatchUrlReferences() {
return myAllowInlineMatchUrlReferences;
}
public boolean isAllowMultipleDelete() { public boolean isAllowMultipleDelete() {
return myAllowMultipleDelete; return myAllowMultipleDelete;
} }
/**
* Should contained IDs be indexed the same way that non-contained IDs are (default is
* <code>true</code>)
*/
public boolean isIndexContainedResources() {
return myIndexContainedResources;
}
public boolean isSchedulingDisabled() { public boolean isSchedulingDisabled() {
return mySchedulingDisabled; return mySchedulingDisabled;
} }
@ -99,6 +121,20 @@ public class DaoConfig {
return mySubscriptionEnabled; 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.
* <p>
* Default is false for now, as this is an experimental feature.
* </p>
* @since 1.5
*/
public void setAllowInlineMatchUrlReferences(boolean theAllowInlineMatchUrlReferences) {
myAllowInlineMatchUrlReferences = theAllowInlineMatchUrlReferences;
}
public void setAllowMultipleDelete(boolean theAllowMultipleDelete) { public void setAllowMultipleDelete(boolean theAllowMultipleDelete) {
myAllowMultipleDelete = theAllowMultipleDelete; myAllowMultipleDelete = theAllowMultipleDelete;
} }
@ -120,6 +156,14 @@ public class DaoConfig {
myIncludeLimit = theIncludeLimit; myIncludeLimit = theIncludeLimit;
} }
/**
* Should contained IDs be indexed the same way that non-contained IDs are (default is
* <code>true</code>)
*/
public void setIndexContainedResources(boolean theIndexContainedResources) {
myIndexContainedResources = theIndexContainedResources;
}
/** /**
* This may be used to optionally register server interceptors directly against the DAOs. * This may be used to optionally register server interceptors directly against the DAOs.
* <p> * <p>

View File

@ -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<ForcedId, Long> {
@Query("SELECT f FROM ForcedId f WHERE f.myResourcePid = :resource_pid")
public ForcedId findByResourcePid(@Param("resource_pid") Long theResourcePid);
}

View File

@ -462,7 +462,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
FhirTerser terser = getContext().newTerser(); FhirTerser terser = getContext().newTerser();
for (DaoMethodOutcome nextOutcome : idToPersistedOutcome.values()) { for (DaoMethodOutcome nextOutcome : idToPersistedOutcome.values()) {
IBaseResource nextResource = (IBaseResource) nextOutcome.getResource(); IBaseResource nextResource = nextOutcome.getResource();
if (nextResource == null) { if (nextResource == null) {
continue; continue;
} }

View File

@ -35,7 +35,8 @@ import javax.persistence.UniqueConstraint;
//@formatter:off //@formatter:off
@Entity() @Entity()
@Table(name = "HFJ_FORCED_ID", uniqueConstraints = { @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 = { @NamedQueries(value = {
@NamedQuery(name = "Q_GET_FORCED_ID", query = "SELECT f FROM ForcedId f WHERE myForcedId = :ID") @NamedQuery(name = "Q_GET_FORCED_ID", query = "SELECT f FROM ForcedId f WHERE myForcedId = :ID")

View File

@ -23,6 +23,7 @@ package ca.uhn.fhir.jpa.entity;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Embeddable; import javax.persistence.Embeddable;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Index;
import javax.persistence.Table; import javax.persistence.Table;
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
@ -34,9 +35,8 @@ import org.hibernate.search.annotations.Field;
//@formatter:off //@formatter:off
@Embeddable @Embeddable
@Entity @Entity
@Table(name = "HFJ_SPIDX_COORDS" /* , indexes = { @Index(name = "IDX_SP_TOKEN", columnList = "SP_SYSTEM,SP_VALUE") } */) @Table(name = "HFJ_SPIDX_COORDS", indexes = {
@org.hibernate.annotations.Table(appliesTo = "HFJ_SPIDX_COORDS", indexes = { @Index(name = "IDX_SP_COORDS", columnList = "RES_TYPE,SP_NAME,SP_LATITUDE,SP_LONGITUDE")
@org.hibernate.annotations.Index(name = "IDX_SP_COORDS", columnNames = { "RES_TYPE", "SP_NAME", "SP_LATITUDE" })
}) })
//@formatter:on //@formatter:on
public class ResourceIndexedSearchParamCoords extends BaseResourceIndexedSearchParam { public class ResourceIndexedSearchParamCoords extends BaseResourceIndexedSearchParam {

View File

@ -144,6 +144,9 @@ public class ResourceTable extends BaseHasResource implements Serializable {
//@formatter:on //@formatter:on
private String myContentText; private String myContentText;
@Column(name = "HAS_CONTAINED", nullable = true)
private boolean myHasContainedResource;
@Column(name = "SP_HAS_LINKS") @Column(name = "SP_HAS_LINKS")
private boolean myHasLinks; private boolean myHasLinks;
@ -158,6 +161,9 @@ public class ResourceTable extends BaseHasResource implements Serializable {
@Column(name = "SP_INDEX_STATUS", nullable = true) @Column(name = "SP_INDEX_STATUS", nullable = true)
private Long myIndexStatus; private Long myIndexStatus;
@Column(name = "IS_CONTAINED", nullable = true)
private boolean myIsContainedResource;
@Column(name = "RES_LANGUAGE", length = MAX_LANGUAGE_LENGTH, nullable = true) @Column(name = "RES_LANGUAGE", length = MAX_LANGUAGE_LENGTH, nullable = true)
private String myLanguage; private String myLanguage;
@ -340,10 +346,18 @@ public class ResourceTable extends BaseHasResource implements Serializable {
return false; return false;
} }
public boolean isHasContainedResource() {
return myHasContainedResource;
}
public boolean isHasLinks() { public boolean isHasLinks() {
return myHasLinks; return myHasLinks;
} }
public boolean isIsContainedResource() {
return myIsContainedResource;
}
public boolean isParamsCoordsPopulated() { public boolean isParamsCoordsPopulated() {
return myParamsCoordsPopulated; return myParamsCoordsPopulated;
} }
@ -376,6 +390,10 @@ public class ResourceTable extends BaseHasResource implements Serializable {
myContentText = theContentText; myContentText = theContentText;
} }
public void setHasContainedResource(boolean theHasContainedResource) {
myHasContainedResource = theHasContainedResource;
}
public void setHasLinks(boolean theHasLinks) { public void setHasLinks(boolean theHasLinks) {
myHasLinks = theHasLinks; myHasLinks = theHasLinks;
} }
@ -388,6 +406,10 @@ public class ResourceTable extends BaseHasResource implements Serializable {
myIndexStatus = theIndexStatus; myIndexStatus = theIndexStatus;
} }
public void setIsContainedResource(boolean theIsContainedResource) {
myIsContainedResource = theIsContainedResource;
}
public void setLanguage(String theLanguage) { public void setLanguage(String theLanguage) {
if (defaultString(theLanguage).length() > MAX_LANGUAGE_LENGTH) { if (defaultString(theLanguage).length() > MAX_LANGUAGE_LENGTH) {
throw new UnprocessableEntityException("Language exceeds maximum length of " + MAX_LANGUAGE_LENGTH + " chars: " + theLanguage); throw new UnprocessableEntityException("Language exceeds maximum length of " + MAX_LANGUAGE_LENGTH + " chars: " + theLanguage);

View File

@ -1,8 +1,9 @@
package ca.uhn.fhir.jpa.dao; package ca.uhn.fhir.jpa.dao;
import static org.mockito.Mockito.mock;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.sql.DriverManager;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; 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.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Before;
import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test; import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test;
import ca.uhn.fhir.model.dstu2.resource.Bundle; import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry; import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
import ca.uhn.fhir.rest.server.IBundleProvider; import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
public class BaseJpaTest { public class BaseJpaTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseJpaTest.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseJpaTest.class);
protected ServletRequestDetails mySrd;
@SuppressWarnings({ "rawtypes" }) @SuppressWarnings({ "rawtypes" })
protected List toList(IBundleProvider theSearch) { protected List toList(IBundleProvider theSearch) {
return theSearch.getResources(0, theSearch.size()); return theSearch.getResources(0, theSearch.size());
} }
@Before
public void beforeCreateSrd() {
mySrd = mock(ServletRequestDetails.class);
}
protected List<IIdType> toUnqualifiedVersionlessIds(Bundle theFound) { protected List<IIdType> toUnqualifiedVersionlessIds(Bundle theFound) {
List<IIdType> retVal = new ArrayList<IIdType>(); List<IIdType> retVal = new ArrayList<IIdType>();
for (Entry next : theFound.getEntry()) { for (Entry next : theFound.getEntry()) {

View File

@ -47,6 +47,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionCallback;
@ -239,14 +240,14 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
public TransactionTemplate newTxTemplate() { public TransactionTemplate newTxTemplate() {
TransactionTemplate retVal = new TransactionTemplate(myTxManager); TransactionTemplate retVal = new TransactionTemplate(myTxManager);
retVal.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW); retVal.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
retVal.afterPropertiesSet(); retVal.afterPropertiesSet();
return retVal; return retVal;
} }
public static void purgeDatabase(final EntityManager entityManager, PlatformTransactionManager theTxManager) { public static void purgeDatabase(final EntityManager entityManager, PlatformTransactionManager theTxManager) {
TransactionTemplate txTemplate = new TransactionTemplate(theTxManager); TransactionTemplate txTemplate = new TransactionTemplate(theTxManager);
txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRED); txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
txTemplate.execute(new TransactionCallback<Void>() { txTemplate.execute(new TransactionCallback<Void>() {
@Override @Override
public Void doInTransaction(TransactionStatus theStatus) { public Void doInTransaction(TransactionStatus theStatus) {

View File

@ -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
}

View File

@ -31,6 +31,7 @@ import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.StringOrListParam; import ca.uhn.fhir.rest.param.StringOrListParam;
import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenParam; 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.Constants;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
@ -46,31 +47,35 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
obs1.setStatus(ObservationStatus.FINAL); obs1.setStatus(ObservationStatus.FINAL);
obs1.setValue(new Quantity(123)); obs1.setValue(new Quantity(123));
obs1.setComments("obs1"); obs1.setComments("obs1");
IIdType id1 = myObservationDao.create(obs1, new ServletRequestDetails()).getId().toUnqualifiedVersionless(); IIdType id1 = myObservationDao.create(obs1, mySrd).getId().toUnqualifiedVersionless();
Observation obs2 = new Observation(); Observation obs2 = new Observation();
obs2.getCode().setText("Diastolic Blood Pressure"); obs2.getCode().setText("Diastolic Blood Pressure");
obs2.setStatus(ObservationStatus.FINAL); obs2.setStatus(ObservationStatus.FINAL);
obs2.setValue(new Quantity(81)); obs2.setValue(new Quantity(81));
IIdType id2 = myObservationDao.create(obs2, new ServletRequestDetails()).getId().toUnqualifiedVersionless(); IIdType id2 = myObservationDao.create(obs2, mySrd).getId().toUnqualifiedVersionless();
SearchParameterMap map; SearchParameterMap map;
map = new SearchParameterMap(); 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))); assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(id1, id2)));
map = new SearchParameterMap(); 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()); assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), empty());
map = new SearchParameterMap(); 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")); map.add(Constants.PARAM_CONTENT, new StringParam("obs1"));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(id1))); assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(id1)));
} }
private ServletRequestDetails mockSrd() {
return new ServletRequestDetails();
}
@Test @Test
@Ignore @Ignore
public void testStringTextSearch() { public void testStringTextSearch() {
@ -78,13 +83,13 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
obs1.getCode().setText("AAAAA"); obs1.getCode().setText("AAAAA");
obs1.setValue(new StringType("Systolic Blood Pressure")); obs1.setValue(new StringType("Systolic Blood Pressure"));
obs1.setStatus(ObservationStatus.FINAL); 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(); Observation obs2 = new Observation();
obs1.getCode().setText("AAAAA"); obs1.getCode().setText("AAAAA");
obs1.setValue(new StringType("Diastolic Blood Pressure")); obs1.setValue(new StringType("Diastolic Blood Pressure"));
obs2.setStatus(ObservationStatus.FINAL); obs2.setStatus(ObservationStatus.FINAL);
IIdType id2 = myObservationDao.create(obs2, new ServletRequestDetails()).getId().toUnqualifiedVersionless(); IIdType id2 = myObservationDao.create(obs2, mockSrd()).getId().toUnqualifiedVersionless();
SearchParameterMap map; SearchParameterMap map;
@ -99,7 +104,7 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
public void testSuggestIgnoresBase64Content() { public void testSuggestIgnoresBase64Content() {
Patient patient = new Patient(); Patient patient = new Patient();
patient.addName().addFamily("testSuggest"); 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(); Media med = new Media();
med.getSubject().setReferenceElement(ptId); med.getSubject().setReferenceElement(ptId);
@ -107,7 +112,7 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
med.getContent().setContentType("LCws"); med.getContent().setContentType("LCws");
med.getContent().setDataElement(new Base64BinaryType(new byte[] {44,44,44,44,44,44,44,44})); med.getContent().setDataElement(new Base64BinaryType(new byte[] {44,44,44,44,44,44,44,44}));
med.getContent().setTitle("bbbb syst"); med.getContent().setTitle("bbbb syst");
myMediaDao.create(med, new ServletRequestDetails()); myMediaDao.create(med, mockSrd());
ourLog.info(myFhirCtx.newJsonParser().encodeResourceToString(med)); ourLog.info(myFhirCtx.newJsonParser().encodeResourceToString(med));
List<Suggestion> output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "press"); List<Suggestion> output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "press");
@ -139,35 +144,35 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
public void testSuggest() { public void testSuggest() {
Patient patient = new Patient(); Patient patient = new Patient();
patient.addName().addFamily("testSuggest"); 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(); Observation obs = new Observation();
obs.getSubject().setReferenceElement(ptId); obs.getSubject().setReferenceElement(ptId);
obs.getCode().setText("ZXCVBNM ASDFGHJKL QWERTYUIOPASDFGHJKL"); obs.getCode().setText("ZXCVBNM ASDFGHJKL QWERTYUIOPASDFGHJKL");
myObservationDao.create(obs, new ServletRequestDetails()); myObservationDao.create(obs, mockSrd());
obs = new Observation(); obs = new Observation();
obs.getSubject().setReferenceElement(ptId); obs.getSubject().setReferenceElement(ptId);
obs.getCode().setText("MNBVCXZ"); obs.getCode().setText("MNBVCXZ");
myObservationDao.create(obs, new ServletRequestDetails()); myObservationDao.create(obs, mockSrd());
obs = new Observation(); obs = new Observation();
obs.getSubject().setReferenceElement(ptId); obs.getSubject().setReferenceElement(ptId);
obs.getCode().setText("ZXC HELLO"); obs.getCode().setText("ZXC HELLO");
obs.addComponent().getCode().setText("HHHHHHHHHH"); obs.addComponent().getCode().setText("HHHHHHHHHH");
myObservationDao.create(obs, new ServletRequestDetails()); myObservationDao.create(obs, mockSrd());
/* /*
* These shouldn't match since they're for another patient * These shouldn't match since they're for another patient
*/ */
patient = new Patient(); patient = new Patient();
patient.addName().addFamily("testSuggest2"); 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(); Observation obs2 = new Observation();
obs2.getSubject().setReferenceElement(ptId2); obs2.getSubject().setReferenceElement(ptId2);
obs2.getCode().setText("ZXCVBNMZZ"); obs2.getCode().setText("ZXCVBNMZZ");
myObservationDao.create(obs2, new ServletRequestDetails()); myObservationDao.create(obs2, mockSrd());
List<Suggestion> output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "ZXCVBNM"); List<Suggestion> output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "ZXCVBNM");
ourLog.info("Found: " + output); ourLog.info("Found: " + output);
@ -212,7 +217,7 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
patient = new Patient(); patient = new Patient();
patient.getText().setDivAsString("<div>DIVAAA</div>"); patient.getText().setDivAsString("<div>DIVAAA</div>");
patient.addName().addGiven("NAMEAAA"); 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 = new SearchParameterMap();
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA")); map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA"));
@ -230,7 +235,7 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
patient.setId(pId1); patient.setId(pId1);
patient.getText().setDivAsString("<div>DIVBBB</div>"); patient.getText().setDivAsString("<div>DIVBBB</div>");
patient.addName().addGiven("NAMEBBB"); patient.addName().addGiven("NAMEBBB");
myPatientDao.update(patient, new ServletRequestDetails()); myPatientDao.update(patient, mockSrd());
map = new SearchParameterMap(); map = new SearchParameterMap();
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA")); map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA"));
@ -254,19 +259,19 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
public void testEverythingInstanceWithContentFilter() { public void testEverythingInstanceWithContentFilter() {
Patient pt1 = new Patient(); Patient pt1 = new Patient();
pt1.addName().addFamily("Everything").addGiven("Arthur"); 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(); Patient pt2 = new Patient();
pt2.addName().addFamily("Everything").addGiven("Arthur"); 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(); Device dev1 = new Device();
dev1.setManufacturer("Some Manufacturer"); 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(); Device dev2 = new Device();
dev2.setManufacturer("Some Manufacturer 2"); dev2.setManufacturer("Some Manufacturer 2");
myDeviceDao.create(dev2, new ServletRequestDetails()).getId().toUnqualifiedVersionless(); myDeviceDao.create(dev2, mockSrd()).getId().toUnqualifiedVersionless();
Observation obs1 = new Observation(); Observation obs1 = new Observation();
obs1.getText().setDivAsString("<div>OBSTEXT1</div>"); obs1.getText().setDivAsString("<div>OBSTEXT1</div>");
@ -274,19 +279,19 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
obs1.getCode().addCoding().setCode("CODE1"); obs1.getCode().addCoding().setCode("CODE1");
obs1.setValue(new StringType("obsvalue1")); obs1.setValue(new StringType("obsvalue1"));
obs1.getDevice().setReferenceElement(devId1); 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(); Observation obs2 = new Observation();
obs2.getSubject().setReferenceElement(ptId1); obs2.getSubject().setReferenceElement(ptId1);
obs2.getCode().addCoding().setCode("CODE2"); obs2.getCode().addCoding().setCode("CODE2");
obs2.setValue(new StringType("obsvalue2")); 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(); Observation obs3 = new Observation();
obs3.getSubject().setReferenceElement(ptId2); obs3.getSubject().setReferenceElement(ptId2);
obs3.getCode().addCoding().setCode("CODE3"); obs3.getCode().addCoding().setCode("CODE3");
obs3.setValue(new StringType("obsvalue3")); obs3.setValue(new StringType("obsvalue3"));
IIdType obsId3 = myObservationDao.create(obs3, new ServletRequestDetails()).getId().toUnqualifiedVersionless(); IIdType obsId3 = myObservationDao.create(obs3, mockSrd()).getId().toUnqualifiedVersionless();
HttpServletRequest request; HttpServletRequest request;
List<String> actual; List<String> actual;
@ -297,16 +302,16 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
param = new StringAndListParam(); param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1"))); 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))); assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId1, devId1)));
param = new StringAndListParam(); param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("obstext1"))); 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))); assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId1, devId1)));
request = mock(HttpServletRequest.class); 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))); assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId1, obsId2, devId1)));
/* /*
@ -317,12 +322,12 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
obs4.getSubject().setReferenceElement(ptId1); obs4.getSubject().setReferenceElement(ptId1);
obs4.getCode().addCoding().setCode("CODE1"); obs4.getCode().addCoding().setCode("CODE1");
obs4.setValue(new StringType("obsvalue1")); 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); assertNotEquals(obsId1.getIdPart(), obsId4.getIdPart(), devId1);
param = new StringAndListParam(); param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1"))); 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))); assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId1, obsId4, devId1)));
/* /*
@ -334,11 +339,11 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
obs1.getSubject().setReferenceElement(ptId1); obs1.getSubject().setReferenceElement(ptId1);
obs1.getCode().addCoding().setCode("CODE2"); obs1.getCode().addCoding().setCode("CODE2");
obs1.setValue(new StringType("obsvalue2")); obs1.setValue(new StringType("obsvalue2"));
myObservationDao.update(obs1, new ServletRequestDetails()); myObservationDao.update(obs1, mockSrd());
param = new StringAndListParam(); param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1"))); 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))); assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId4)));
} }
@ -347,38 +352,38 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
public void testEverythingTypeWithContentFilter() { public void testEverythingTypeWithContentFilter() {
Patient pt1 = new Patient(); Patient pt1 = new Patient();
pt1.addName().addFamily("Everything").addGiven("Arthur"); 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(); Patient pt2 = new Patient();
pt2.addName().addFamily("Everything").addGiven("Arthur"); 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(); Device dev1 = new Device();
dev1.setManufacturer("Some Manufacturer"); 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(); Device dev2 = new Device();
dev2.setManufacturer("Some Manufacturer 2"); dev2.setManufacturer("Some Manufacturer 2");
IIdType devId2 = myDeviceDao.create(dev2, new ServletRequestDetails()).getId().toUnqualifiedVersionless(); myDeviceDao.create(dev2, mockSrd()).getId().toUnqualifiedVersionless();
Observation obs1 = new Observation(); Observation obs1 = new Observation();
obs1.getSubject().setReferenceElement(ptId1); obs1.getSubject().setReferenceElement(ptId1);
obs1.getCode().addCoding().setCode("CODE1"); obs1.getCode().addCoding().setCode("CODE1");
obs1.setValue(new StringType("obsvalue1")); obs1.setValue(new StringType("obsvalue1"));
obs1.getDevice().setReferenceElement(devId1); 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(); Observation obs2 = new Observation();
obs2.getSubject().setReferenceElement(ptId1); obs2.getSubject().setReferenceElement(ptId1);
obs2.getCode().addCoding().setCode("CODE2"); obs2.getCode().addCoding().setCode("CODE2");
obs2.setValue(new StringType("obsvalue2")); 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(); Observation obs3 = new Observation();
obs3.getSubject().setReferenceElement(ptId2); obs3.getSubject().setReferenceElement(ptId2);
obs3.getCode().addCoding().setCode("CODE3"); obs3.getCode().addCoding().setCode("CODE3");
obs3.setValue(new StringType("obsvalue3")); obs3.setValue(new StringType("obsvalue3"));
IIdType obsId3 = myObservationDao.create(obs3, new ServletRequestDetails()).getId().toUnqualifiedVersionless(); IIdType obsId3 = myObservationDao.create(obs3, mockSrd()).getId().toUnqualifiedVersionless();
HttpServletRequest request; HttpServletRequest request;
List<String> actual; List<String> actual;
@ -389,11 +394,11 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
param = new StringAndListParam(); param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1"))); 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))); assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId1, devId1)));
request = mock(HttpServletRequest.class); 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))); assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId1, obsId2, devId1, ptId2, obsId3)));
/* /*
@ -404,12 +409,12 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
obs4.getSubject().setReferenceElement(ptId1); obs4.getSubject().setReferenceElement(ptId1);
obs4.getCode().addCoding().setCode("CODE1"); obs4.getCode().addCoding().setCode("CODE1");
obs4.setValue(new StringType("obsvalue1")); 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); assertNotEquals(obsId1.getIdPart(), obsId4.getIdPart(), devId1);
param = new StringAndListParam(); param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1"))); 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))); assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId1, obsId4, devId1)));
/* /*
@ -421,11 +426,11 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
obs1.getSubject().setReferenceElement(ptId1); obs1.getSubject().setReferenceElement(ptId1);
obs1.getCode().addCoding().setCode("CODE2"); obs1.getCode().addCoding().setCode("CODE2");
obs1.setValue(new StringType("obsvalue2")); obs1.setValue(new StringType("obsvalue2"));
myObservationDao.update(obs1, new ServletRequestDetails()); myObservationDao.update(obs1, mockSrd());
param = new StringAndListParam(); param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1"))); 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))); assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId4)));
} }
@ -443,7 +448,7 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
patient = new Patient(); patient = new Patient();
patient.getText().setDivAsString("<div>DIVAAA</div>"); patient.getText().setDivAsString("<div>DIVAAA</div>");
patient.addName().addGiven("NAMEAAA"); 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 = new SearchParameterMap();
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA")); map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA"));
@ -461,7 +466,7 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
patient.setId(pId1); patient.setId(pId1);
patient.getText().setDivAsString("<div>DIVBBB</div>"); patient.getText().setDivAsString("<div>DIVBBB</div>");
patient.addName().addGiven("NAMEBBB"); patient.addName().addGiven("NAMEBBB");
myPatientDao.update(patient, null, false, new ServletRequestDetails()); myPatientDao.update(patient, null, false, mockSrd());
map = new SearchParameterMap(); map = new SearchParameterMap();
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA")); 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")); map.add(Constants.PARAM_CONTENT, new StringParam("NAMEBBB"));
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), not(contains(toValues(pId1)))); 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 = new SearchParameterMap();
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA")); map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA"));
@ -498,18 +503,18 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
Patient patient = new Patient(); Patient patient = new Patient();
patient.addName().addGiven(methodName); patient.addName().addGiven(methodName);
patient.addAddress().addLine("My fulltext address"); 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(); Observation obs = new Observation();
obs.getSubject().setReferenceElement(pId1); obs.getSubject().setReferenceElement(pId1);
obs.setValue(new StringType("This is the FULLtext of the observation")); 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 = new Observation();
obs.getSubject().setReferenceElement(pId1); obs.getSubject().setReferenceElement(pId1);
obs.setValue(new StringType("Another fullText")); obs.setValue(new StringType("Another fullText"));
IIdType oId2 = myObservationDao.create(obs, new ServletRequestDetails()).getId().toUnqualifiedVersionless(); IIdType oId2 = myObservationDao.create(obs, mockSrd()).getId().toUnqualifiedVersionless();
List<String> patients; List<String> patients;
SearchParameterMap params; SearchParameterMap params;

View File

@ -23,7 +23,6 @@ import java.util.Set;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils; 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.CodeType;
import org.hl7.fhir.dstu3.model.ConceptMap; import org.hl7.fhir.dstu3.model.ConceptMap;
import org.hl7.fhir.dstu3.model.ContactPoint.ContactPointSystem; 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.Substance;
import org.hl7.fhir.dstu3.model.TemporalPrecisionEnum; import org.hl7.fhir.dstu3.model.TemporalPrecisionEnum;
import org.hl7.fhir.dstu3.model.ValueSet; 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.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.Ignore; import org.junit.Ignore;
@ -586,21 +586,21 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
} }
{ {
Map<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>(); Map<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>();
params.put(BaseResource.SP_RES_LANGUAGE, new StringParam("en_CA")); params.put(IAnyResource.SP_RES_LANGUAGE, new StringParam("en_CA"));
List<IBaseResource> patients = toList(myPatientDao.search(params)); List<IBaseResource> patients = toList(myPatientDao.search(params));
assertEquals(1, patients.size()); assertEquals(1, patients.size());
assertEquals(id1.toUnqualifiedVersionless(), patients.get(0).getIdElement().toUnqualifiedVersionless()); assertEquals(id1.toUnqualifiedVersionless(), patients.get(0).getIdElement().toUnqualifiedVersionless());
} }
{ {
Map<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>(); Map<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>();
params.put(BaseResource.SP_RES_LANGUAGE, new StringParam("en_US")); params.put(IAnyResource.SP_RES_LANGUAGE, new StringParam("en_US"));
List<Patient> patients = toList(myPatientDao.search(params)); List<Patient> patients = toList(myPatientDao.search(params));
assertEquals(1, patients.size()); assertEquals(1, patients.size());
assertEquals(id2.toUnqualifiedVersionless(), patients.get(0).getIdElement().toUnqualifiedVersionless()); assertEquals(id2.toUnqualifiedVersionless(), patients.get(0).getIdElement().toUnqualifiedVersionless());
} }
{ {
Map<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>(); Map<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>();
params.put(BaseResource.SP_RES_LANGUAGE, new StringParam("en_GB")); params.put(IAnyResource.SP_RES_LANGUAGE, new StringParam("en_GB"));
List<Patient> patients = toList(myPatientDao.search(params)); List<Patient> patients = toList(myPatientDao.search(params));
assertEquals(0, patients.size()); assertEquals(0, patients.size());
} }
@ -629,18 +629,18 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
} }
{ {
SearchParameterMap params = new SearchParameterMap(); 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)); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1, id2));
} }
{ {
SearchParameterMap params = new SearchParameterMap(); 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)); params.setLastUpdated(new DateRangeParam(betweenTime, null));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id2)); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id2));
} }
{ {
SearchParameterMap params = new SearchParameterMap(); 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)); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1));
} }
{ {
@ -648,7 +648,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
StringAndListParam and = new StringAndListParam(); 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")).addOr(new StringParam("ZZZZ")));
and.addAnd(new StringOrListParam().addOr(new StringParam("en_CA"))); 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)); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1));
} }
{ {
@ -656,7 +656,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
StringAndListParam and = new StringAndListParam(); 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")).addOr(new StringParam("ZZZZ")));
and.addAnd(new StringOrListParam().addOr(new StringParam("ZZZZZ"))); 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()); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), empty());
} }
{ {
@ -664,7 +664,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
StringAndListParam and = new StringAndListParam(); StringAndListParam and = new StringAndListParam();
and.addAnd(new StringOrListParam().addOr(new StringParam("ZZZZZ"))); and.addAnd(new StringOrListParam().addOr(new StringParam("ZZZZZ")));
and.addAnd(new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("ZZZZ"))); 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()); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), empty());
} }
{ {
@ -672,7 +672,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
StringAndListParam and = new StringAndListParam(); 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")).addOr(new StringParam("ZZZZ")));
and.addAnd(new StringOrListParam().addOr(new StringParam("")).addOr(new StringParam(null))); 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)); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1));
} }
{ {
@ -681,7 +681,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
StringAndListParam and = new StringAndListParam(); 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")).addOr(new StringParam("ZZZZ")));
and.addAnd(new StringOrListParam().addOr(new StringParam("")).addOr(new StringParam(null))); 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)); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1));
} }
{ {
@ -689,7 +689,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
StringAndListParam and = new StringAndListParam(); 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")).addOr(new StringParam("ZZZZ")));
and.addAnd(new StringOrListParam().addOr(new StringParam("")).addOr(new StringParam(null))); 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())); params.add("_id", new StringParam(id1.getIdPart()));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1)); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1));
} }
@ -767,8 +767,6 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
@Test @Test
public void testSearchLastUpdatedParamWithComparator() throws InterruptedException { public void testSearchLastUpdatedParamWithComparator() throws InterruptedException {
String methodName = "testSearchLastUpdatedParamWithComparator";
IIdType id0; IIdType id0;
{ {
Patient patient = new Patient(); Patient patient = new Patient();
@ -781,7 +779,6 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
Thread.sleep(sleep); Thread.sleep(sleep);
DateTimeType beforeAny = new DateTimeType(new Date(), TemporalPrecisionEnum.MILLI);
IIdType id1a; IIdType id1a;
{ {
Patient patient = new Patient(); Patient patient = new Patient();
@ -815,12 +812,12 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), containsInAnyOrder(id1a, id1b)); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), containsInAnyOrder(id1a, id1b));
map = new SearchParameterMap(); 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()); ourLog.info("Searching: {}", map.getLastUpdated());
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), containsInAnyOrder(id1a, id1b)); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), containsInAnyOrder(id1a, id1b));
map = new SearchParameterMap(); 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()); ourLog.info("Searching: {}", map.getLastUpdated());
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), containsInAnyOrder(id1a, id1b)); assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), containsInAnyOrder(id1a, id1b));
@ -1373,7 +1370,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
QuantityParam param; QuantityParam param;
Set<Long> found; Set<Long> 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); found = myObservationDao.searchForIds("value-quantity", param);
int initialSize = found.size(); int initialSize = found.size();
@ -1384,19 +1381,19 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
myObservationDao.create(o, new ServletRequestDetails()); 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); found = myObservationDao.searchForIds("value-quantity", param);
assertEquals(1 + initialSize, found.size()); 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); found = myObservationDao.searchForIds("value-quantity", param);
assertEquals(1, found.size()); 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); found = myObservationDao.searchForIds("value-quantity", param);
assertEquals(1, found.size()); 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); found = myObservationDao.searchForIds("value-quantity", param);
assertEquals(1, found.size()); assertEquals(1, found.size());
@ -1406,8 +1403,8 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
public void testSearchWithEmptySort() { public void testSearchWithEmptySort() {
SearchParameterMap criteriaUrl = new SearchParameterMap(); SearchParameterMap criteriaUrl = new SearchParameterMap();
DateRangeParam range = new DateRangeParam(); DateRangeParam range = new DateRangeParam();
range.setLowerBound(new DateParam(QuantityCompararatorEnum.GREATERTHAN, 1000000)); range.setLowerBound(new DateParam(ParamPrefixEnum.GREATERTHAN, 1000000));
range.setUpperBound(new DateParam(QuantityCompararatorEnum.LESSTHAN, 2000000)); range.setUpperBound(new DateParam(ParamPrefixEnum.LESSTHAN, 2000000));
criteriaUrl.setLastUpdated(range); criteriaUrl.setLastUpdated(range);
criteriaUrl.setSort(new SortSpec(Constants.PARAM_LASTUPDATED, SortOrderEnum.ASC)); criteriaUrl.setSort(new SortSpec(Constants.PARAM_LASTUPDATED, SortOrderEnum.ASC));
IBundleProvider results = myObservationDao.search(criteriaUrl); IBundleProvider results = myObservationDao.search(criteriaUrl);
@ -1555,7 +1552,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
{ {
SearchParameterMap params = new SearchParameterMap(); 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()); params.addInclude(Organization.INCLUDE_PARTOF.asNonRecursive());
List<IIdType> resources = toUnqualifiedVersionlessIds(myOrganizationDao.search(params)); List<IIdType> resources = toUnqualifiedVersionlessIds(myOrganizationDao.search(params));
assertThat(resources, contains(orgId, parentOrgId)); assertThat(resources, contains(orgId, parentOrgId));
@ -1597,7 +1594,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
{ {
SearchParameterMap params = new SearchParameterMap(); 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()); params.addInclude(Organization.INCLUDE_PARTOF.asRecursive());
List<IIdType> resources = toUnqualifiedVersionlessIds(myOrganizationDao.search(params)); List<IIdType> resources = toUnqualifiedVersionlessIds(myOrganizationDao.search(params));
ourLog.info(resources.toString()); ourLog.info(resources.toString());

View File

@ -42,8 +42,10 @@ import org.hl7.fhir.dstu3.model.UriType;
import org.hl7.fhir.dstu3.model.ValueSet; import org.hl7.fhir.dstu3.model.ValueSet;
import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.After;
import org.junit.Test; import org.junit.Test;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.support.TransactionTemplate;
@ -112,7 +114,7 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
// Try making the resource unparseable // Try making the resource unparseable
TransactionTemplate template = new TransactionTemplate(myTxManager); TransactionTemplate template = new TransactionTemplate(myTxManager);
template.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW); template.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
template.execute(new TransactionCallback<ResourceTable>() { template.execute(new TransactionCallback<ResourceTable>() {
@Override @Override
public ResourceTable doInTransaction(TransactionStatus theStatus) { 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 @Test
public void testTransactionCreateMatchUrlWithTwoMatch() { public void testTransactionCreateMatchUrlWithTwoMatch() {
String methodName = "testTransactionCreateMatchUrlWithTwoMatch"; String methodName = "testTransactionCreateMatchUrlWithTwoMatch";

View File

@ -50,6 +50,7 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
retVal.setSubscriptionPollDelay(5000); retVal.setSubscriptionPollDelay(5000);
retVal.setSubscriptionPurgeInactiveAfterMillis(DateUtils.MILLIS_PER_HOUR); retVal.setSubscriptionPurgeInactiveAfterMillis(DateUtils.MILLIS_PER_HOUR);
retVal.setAllowMultipleDelete(true); retVal.setAllowMultipleDelete(true);
retVal.setAllowInlineMatchUrlReferences(true);
return retVal; return retVal;
} }

View File

@ -46,6 +46,7 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
retVal.setSubscriptionPollDelay(5000); retVal.setSubscriptionPollDelay(5000);
retVal.setSubscriptionPurgeInactiveAfterMillis(DateUtils.MILLIS_PER_HOUR); retVal.setSubscriptionPurgeInactiveAfterMillis(DateUtils.MILLIS_PER_HOUR);
retVal.setAllowMultipleDelete(true); retVal.setAllowMultipleDelete(true);
retVal.setAllowInlineMatchUrlReferences(true);
return retVal; return retVal;
} }

View File

@ -1,7 +1,9 @@
package ca.uhn.fhir.rest.client; package ca.uhn.fhir.rest.client;
import static org.junit.Assert.*; import static org.junit.Assert.assertArrayEquals;
import static org.mockito.Mockito.*; import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -17,11 +19,9 @@ import org.apache.http.message.BasicStatusLine;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs; import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
import ca.uhn.fhir.context.FhirContext; 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.Binary;
import ca.uhn.fhir.model.dstu.resource.Conformance; import ca.uhn.fhir.model.dstu.resource.Conformance;
import ca.uhn.fhir.model.dstu.resource.Patient; import ca.uhn.fhir.model.dstu.resource.Patient;
@ -48,7 +48,7 @@ public class BinaryClientTest {
httpClient = mock(HttpClient.class, new ReturnsDeepStubs()); httpClient = mock(HttpClient.class, new ReturnsDeepStubs());
ctx.getRestfulClientFactory().setHttpClient(httpClient); ctx.getRestfulClientFactory().setHttpClient(httpClient);
ctx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.NEVER); ctx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs()); httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
} }
@ -59,7 +59,7 @@ public class BinaryClientTest {
when(httpClient.execute(capt.capture())).thenReturn(httpResponse); when(httpClient.execute(capt.capture())).thenReturn(httpResponse);
when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); 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().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"); IClient client = ctx.newRestfulClient(IClient.class, "http://foo");
Binary resp = client.read(new IdDt("http://foo/Patient/123")); Binary resp = client.read(new IdDt("http://foo/Patient/123"));
@ -72,13 +72,6 @@ public class BinaryClientTest {
assertArrayEquals(new byte[] { 1, 2, 3, 4 }, resp.getContent()); assertArrayEquals(new byte[] { 1, 2, 3, 4 }, resp.getContent());
} }
public static void main(String[] args) {
IClient c = Mockito.mock(IClient.class, new ReturnsDeepStubs());
}
@Test @Test
public void testCreate() throws Exception { public void testCreate() throws Exception {
Binary res = new Binary(); Binary res = new Binary();
@ -92,29 +85,23 @@ public class BinaryClientTest {
when(httpResponse.getEntity().getContent()).thenReturn(new ByteArrayInputStream(new byte[] {})); when(httpResponse.getEntity().getContent()).thenReturn(new ByteArrayInputStream(new byte[] {}));
IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); IClient client = ctx.newRestfulClient(IClient.class, "http://foo");
MethodOutcome resp = client.create(res); client.create(res);
assertEquals(HttpPost.class, capt.getValue().getClass()); assertEquals(HttpPost.class, capt.getValue().getClass());
HttpPost post = (HttpPost) capt.getValue(); HttpPost post = (HttpPost) capt.getValue();
assertEquals("http://foo/Binary", post.getURI().toString()); 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())); 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 { private interface IClient extends IBasicClient {
@Read(type=Binary.class) @Read(type = Binary.class)
public Binary read(@IdParam IdDt theBinary); public Binary read(@IdParam IdDt theBinary);
@Create(type=Binary.class) @Create(type = Binary.class)
public MethodOutcome create(@ResourceParam Binary theBinary); public MethodOutcome create(@ResourceParam Binary theBinary);
} }

View File

@ -173,8 +173,8 @@ public class DynamicSearchTest {
@Override @Override
public List<RuntimeSearchParam> getSearchParameters() { public List<RuntimeSearchParam> getSearchParameters() {
ArrayList<RuntimeSearchParam> retVal = new ArrayList<RuntimeSearchParam>(); ArrayList<RuntimeSearchParam> retVal = new ArrayList<RuntimeSearchParam>();
retVal.add(new RuntimeSearchParam("param1", "This is the first parameter", "Patient.param1", RestSearchParameterTypeEnum.STRING)); 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)); retVal.add(new RuntimeSearchParam("param2", "This is the second parameter", "Patient.param2", RestSearchParameterTypeEnum.DATE, null));
return retVal; return retVal;
} }

View File

@ -143,7 +143,7 @@ public class GenericClientDstu2Test {
client.fetchConformance().ofType(Conformance.class).execute(); client.fetchConformance().ofType(Conformance.class).execute();
assertEquals("http://example.com/fhir/metadata", capt.getAllValues().get(idx).getURI().toASCIIString()); assertEquals("http://example.com/fhir/metadata", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals(1, capt.getAllValues().get(idx).getHeaders("Accept").length); 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++; idx++;
client.fetchConformance().ofType(Conformance.class).encodedJson().execute(); 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("FAMILY", resp.getName().get(0).getFamily().get(0).getValue());
assertEquals("http://" + methodName + ".example.com/fhir/metadata", capt.getAllValues().get(0).getURI().toASCIIString()); assertEquals("http://" + methodName + ".example.com/fhir/metadata", capt.getAllValues().get(0).getURI().toASCIIString());
assertEquals(1, capt.getAllValues().get(0).getHeaders("Accept").length); 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_XML));
assertThat(capt.getAllValues().get(0).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_JSON)); 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("http://" + methodName + ".example.com/fhir/Patient/123", capt.getAllValues().get(1).getURI().toASCIIString());
assertEquals(1, capt.getAllValues().get(1).getHeaders("Accept").length); 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_XML));
assertThat(capt.getAllValues().get(1).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_JSON)); assertThat(capt.getAllValues().get(1).getHeaders("Accept")[0].getValue(), containsString(Constants.CT_FHIR_JSON));
} }

View File

@ -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<HttpUriRequest> capt) throws IOException {
byte[] body = IOUtils.toByteArray(((HttpEntityEnclosingRequestBase) capt.getAllValues().get(0)).getEntity().getContent());
return body;
}
private String extractBodyAsString(ArgumentCaptor<HttpUriRequest> 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<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
@Override
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8"));
}
});
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
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<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
@Override
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8"));
}
});
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
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<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
@Override
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8"));
}
});
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
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<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
@Override
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8"));
}
});
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
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("<div>A PATIENT</div>", outputPt.getText().getDivAsString());
}
private void validateUserAgent(ArgumentCaptor<HttpUriRequest> 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();
}
}

View File

@ -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"));
}
}
}

View File

@ -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();
}
}

View File

@ -228,7 +228,7 @@ public class TinderStructuresMojo extends AbstractMojo {
String dtOutputDir = "target/generated-sources/tinder/ca/uhn/fhir/model/dev/composite"; String dtOutputDir = "target/generated-sources/tinder/ca/uhn/fhir/model/dev/composite";
ResourceGeneratorUsingSpreadsheet rp = new ResourceGeneratorUsingSpreadsheet("dstu2", "."); ResourceGeneratorUsingSpreadsheet rp = new ResourceGeneratorUsingSpreadsheet("dstu2", ".");
rp.setBaseResourceNames(Arrays.asList( "supplyrequest" rp.setBaseResourceNames(Arrays.asList( "patient", "auditevent" , "observation"
// //, "contract" // //, "contract"
// "valueset", "organization", "location" // "valueset", "organization", "location"
// , "observation", "conformance" // , "observation", "conformance"

View File

@ -1,5 +1,8 @@
package ca.uhn.fhir.tinder.model; package ca.uhn.fhir.tinder.model;
import java.util.ArrayList;
import java.util.List;
public class Resource extends BaseRootType { public class Resource extends BaseRootType {
@Override @Override
@ -20,4 +23,20 @@ public class Resource extends BaseRootType {
return name; return name;
} }
public SearchParameter getSearchParameterByName(String theName) {
for (SearchParameter next : getSearchParameters()) {
if (next.getName().equalsIgnoreCase(theName)) {
return next;
}
}
return null;
}
public List<String> getSearchParameterNames() {
ArrayList<String> retVal = new ArrayList<String>();
for (SearchParameter next : getSearchParameters()) {
retVal.add(next.getName());
}
return retVal;
}
} }

View File

@ -10,6 +10,7 @@ import org.apache.commons.lang3.StringUtils;
public class SearchParameter { public class SearchParameter {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParameter.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParameter.class);
private List<String> myCompartments = new ArrayList<String>();
private List<String> myCompositeOf; private List<String> myCompositeOf;
private List<String> myCompositeTypes; private List<String> myCompositeTypes;
private String myDescription; private String myDescription;
@ -18,7 +19,6 @@ public class SearchParameter {
private String myResourceName; private String myResourceName;
private List<String> myTargetTypes; private List<String> myTargetTypes;
private String myType; private String myType;
private String myVersion; private String myVersion;
public SearchParameter(String theVersion, String theResourceName) { public SearchParameter(String theVersion, String theResourceName) {
@ -26,6 +26,14 @@ public class SearchParameter {
this.myResourceName = theResourceName; this.myResourceName = theResourceName;
} }
public void addCompartment(String theCompartment) {
myCompartments.add(theCompartment);
}
public List<String> getCompartments() {
return myCompartments;
}
public List<String> getCompositeOf() { public List<String> getCompositeOf() {
if (myCompositeOf == null) { if (myCompositeOf == null) {
myCompositeOf = new ArrayList<String>(); myCompositeOf = new ArrayList<String>();

View File

@ -16,6 +16,7 @@ import java.util.Set;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.WordUtils; import org.apache.commons.lang3.text.WordUtils;
import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
@ -404,7 +405,7 @@ public abstract class BaseStructureSpreadsheetParser extends BaseStructureParser
/** /**
* Subclasses may override * Subclasses may override
*/ */
protected void postProcess(BaseElement theTarget) { protected void postProcess(BaseElement theTarget) throws MojoFailureException {
// nothing // nothing
} }

View File

@ -1,20 +1,31 @@
package ca.uhn.fhir.tinder.parser; package ca.uhn.fhir.tinder.parser;
import static org.apache.commons.lang3.StringUtils.isBlank;
import java.io.InputStream; import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugin.MojoFailureException;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; 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; import ca.uhn.fhir.tinder.util.XMLUtils;
public class CompartmentParser { public class CompartmentParser {
private String myVersion; private String myVersion;
private Resource myResourceDef;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CompartmentParser.class); 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; myVersion = theVersion;
myResourceDef = theResourceDef;
} }
public void parse() throws Exception { 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); 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<Integer, String> col2compartment = new HashMap<Integer, String>();
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);
}
}
} }
} }

View File

@ -22,7 +22,7 @@ import com.google.common.reflect.ClassPath.ClassInfo;
public class DatatypeGeneratorUsingSpreadsheet extends BaseStructureSpreadsheetParser { public class DatatypeGeneratorUsingSpreadsheet extends BaseStructureSpreadsheetParser {
@Override @Override
protected void postProcess(BaseElement theTarget) { protected void postProcess(BaseElement theTarget) throws MojoFailureException {
super.postProcess(theTarget); super.postProcess(theTarget);
/* /*

View File

@ -26,12 +26,21 @@ public class ResourceGeneratorUsingSpreadsheet extends BaseStructureSpreadsheetP
} }
@Override @Override
protected void postProcess(BaseElement theTarget) { protected void postProcess(BaseElement theTarget) throws MojoFailureException {
super.postProcess(theTarget); super.postProcess(theTarget);
if ("Bundle".equals(theTarget.getName())) { if ("Bundle".equals(theTarget.getName())) {
addEverythingToSummary(theTarget); 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) { private void addEverythingToSummary(BaseElement theTarget) {

View File

@ -56,6 +56,13 @@ public class ${className} extends ca.uhn.fhir.model.${version}.resource.BaseReso
* </p> * </p>
*/ */
@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} ) @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}"; public static final String $param.constantName = "${param.name}";
/** /**

View File

@ -59,6 +59,50 @@
<action type="add"> <action type="add">
JPA server now supports :above and :below qualifiers on URI search params JPA server now supports :above and :below qualifiers on URI search params
</action> </action>
<action type="add">
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.
</action>
<action type="add">
The server no longer adds a
<![CDATA[<code>WWW-Authenticate</code>]]>
header to the response if any resource provider code throws an
<![CDATA[<code>AuthenticationException</code>]]>. 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.
</action>
<action type="fix">
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!
</action>
<action type="fix">
Handling of Binary resources containing embedded FHIR resources for
create/update/etc operations has been corrected per the FHIR rules
outlined at
<a href="http://hl7.org/fhir/binary.html">Binary Resource</a> in both
the client and server.
<![CDATA[<br/><br/>]]>
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.
<![CDATA[<br/><br/>]]>
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.
</action>
<action type="add"> <action type="add">
The RequestDetails and ActionRequestDetails objects which are passed to The RequestDetails and ActionRequestDetails objects which are passed to
server interceptor methods and may also be used as server provider method server interceptor methods and may also be used as server provider method

View File

@ -115,8 +115,9 @@
Update methods must be annotated with the Update methods must be annotated with the
<a href="./apidocs/ca/uhn/fhir/rest/annotation/Update.html">@Update</a> <a href="./apidocs/ca/uhn/fhir/rest/annotation/Update.html">@Update</a>
annotation, and have a parameter annotated with the annotation, and have a parameter annotated with the
<a href="./apidocs/ca/uhn/fhir/rest/annotation/ResourceParam.html">@Resource</a> <a href="./apidocs/ca/uhn/fhir/rest/annotation/ResourceParam.html">@ResourceParam</a>
annotation. This parameter contains the resource instance to be created. annotation. This parameter contains the resource instance to be created.
See the <a href="./apidocs/ca/uhn/fhir/rest/annotation/ResourceParam.html">@ResourceParam</a> for information on the types allowed for this parameter (resource types, String, byte[]).
</p> </p>
<p> <p>
In addition, the method may optionally have a parameter annotated with the In addition, the method may optionally have a parameter annotated with the
@ -316,8 +317,9 @@
Create methods must be annotated with the Create methods must be annotated with the
<a href="./apidocs/ca/uhn/fhir/rest/annotation/Create.html">@Create</a> <a href="./apidocs/ca/uhn/fhir/rest/annotation/Create.html">@Create</a>
annotation, and have a single parameter annotated with the annotation, and have a single parameter annotated with the
<a href="./apidocs/ca/uhn/fhir/rest/annotation/ResourceParam.html">@Resource</a> <a href="./apidocs/ca/uhn/fhir/rest/annotation/ResourceParam.html">@ResourceParam</a>
annotation. This parameter contains the resource instance to be created. annotation. This parameter contains the resource instance to be created.
See the <a href="./apidocs/ca/uhn/fhir/rest/annotation/ResourceParam.html">@ResourceParam</a> for information on the types allowed for this parameter (resource types, String, byte[]).
</p> </p>
<p> <p>
Create methods must return an object of type Create methods must return an object of type
@ -1104,7 +1106,7 @@
Validate methods must be annotated with the Validate methods must be annotated with the
<a href="./apidocs/ca/uhn/fhir/rest/annotation/Validate.html">@Validate</a> <a href="./apidocs/ca/uhn/fhir/rest/annotation/Validate.html">@Validate</a>
annotation, and have a parameter annotated with the annotation, and have a parameter annotated with the
<a href="./apidocs/ca/uhn/fhir/rest/annotation/ResourceParam.html">@Resource</a> <a href="./apidocs/ca/uhn/fhir/rest/annotation/ResourceParam.html">@ResourceParam</a>
annotation. This parameter contains the resource instance to be created. annotation. This parameter contains the resource instance to be created.
</p> </p>
<p> <p>