Clean up metadata parsing in XML parser

This commit is contained in:
jamesagnew 2015-01-10 13:44:40 -05:00
parent 51f58f6165
commit 96fe70de59
20 changed files with 333 additions and 192 deletions

View File

@ -433,4 +433,11 @@ public class FhirContext {
return new FhirContext(FhirVersionEnum.DEV);
}
/**
* Creates and returns a new FhirContext with version {@link FhirVersionEnum#DEV}
*/
public static FhirContext forDstu2() {
return new FhirContext(FhirVersionEnum.DEV);
}
}

View File

@ -36,6 +36,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.model.base.resource.ResourceMetadataMap;
import ca.uhn.fhir.model.primitive.BoundCodeDt;
import ca.uhn.fhir.model.primitive.DecimalDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.IntegerDt;
@ -160,27 +161,6 @@ public class Bundle extends BaseBundle /* implements IElement */{
// String resourceType = theContext.getResourceDefinition(theResource).getName();
String linkSearch = ResourceMetadataKeyEnum.LINK_SEARCH.get(theResource);
if (isNotBlank(linkSearch)) {
if (!UrlUtil.isAbsolute(linkSearch)) {
linkSearch = (theServerBase + "/" + linkSearch);
}
entry.getLinkSearch().setValue(linkSearch);
}
String linkAlternate = ResourceMetadataKeyEnum.LINK_ALTERNATE.get(theResource);
if (isNotBlank(linkAlternate)) {
if (!UrlUtil.isAbsolute(linkAlternate)) {
linkSearch = (theServerBase + "/" + linkAlternate);
}
entry.getLinkAlternate().setValue(linkSearch);
}
BundleEntryStatusEnum entryStatus = ResourceMetadataKeyEnum.ENTRY_STATUS.get(theResource);
if (entryStatus != null) {
entry.getStatus().setValueAsEnum(entryStatus);
}
}
}
@ -204,7 +184,7 @@ public class Bundle extends BaseBundle /* implements IElement */{
IdDt previous = ResourceMetadataKeyEnum.PREVIOUS_ID.get(theResource);
if (previous != null) {
entry.getLinkAlternate().setValue(previous.withServerBase(theServerBase, def.getName()));
entry.getLinkAlternate().setValue(previous.withServerBase(theServerBase, def.getName()).getValue());
}
TagList tagList = ResourceMetadataKeyEnum.TAG_LIST.get(theResource);
@ -214,6 +194,32 @@ public class Bundle extends BaseBundle /* implements IElement */{
}
}
String linkSearch = ResourceMetadataKeyEnum.LINK_SEARCH.get(theResource);
if (isNotBlank(linkSearch)) {
if (!UrlUtil.isAbsolute(linkSearch)) {
linkSearch = (theServerBase + "/" + linkSearch);
}
entry.getLinkSearch().setValue(linkSearch);
}
String linkAlternate = ResourceMetadataKeyEnum.LINK_ALTERNATE.get(theResource);
if (isNotBlank(linkAlternate)) {
if (!UrlUtil.isAbsolute(linkAlternate)) {
linkSearch = (theServerBase + "/" + linkAlternate);
}
entry.getLinkAlternate().setValue(linkSearch);
}
BundleEntryStatusEnum entryStatus = ResourceMetadataKeyEnum.ENTRY_STATUS.get(theResource);
if (entryStatus != null) {
entry.getStatus().setValueAsEnum(entryStatus);
}
DecimalDt entryScore = ResourceMetadataKeyEnum.ENTRY_SCORE.get(theResource);
if (entryScore != null) {
entry.setScore(entryScore);
}
return entry;
}

View File

@ -27,8 +27,11 @@ import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import ca.uhn.fhir.model.primitive.DecimalDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.model.valueset.BundleEntryStatusEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
@ -289,6 +292,29 @@ public abstract class ResourceMetadataKeyEnum<T> {
}
};
/**
* Denotes the search score which a given resource should match in a transaction. See the
* FHIR transaction definition for information about this. Corresponds to
* the value in <code>Bundle.entry.score</code> in a Bundle resource.
* <p>
* Note that search URL is only used in FHIR DSTU2 and later.
* </p>
* <p>
* Values for this key are of type <b>{@link DecimalDt}</b>
* </p>
*/
public static final ResourceMetadataKeyEnum<DecimalDt> ENTRY_SCORE = new ResourceMetadataKeyEnum<DecimalDt>("ENTRY_SCORE") {
@Override
public DecimalDt get(IResource theResource) {
return getDecimalFromMetadataOrNullIfNone(theResource.getResourceMetadata(), ENTRY_SCORE);
}
@Override
public void put(IResource theResource, DecimalDt theObject) {
theResource.getResourceMetadata().put(ENTRY_SCORE, theObject);
}
};
private final String myValue;
@ -374,6 +400,50 @@ public abstract class ResourceMetadataKeyEnum<T> {
+ InstantDt.class.getCanonicalName());
}
private static StringDt getStringDtFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum<?>, Object> theResourceMetadata, ResourceMetadataKeyEnum<StringDt> theKey) {
Object retValObj = theResourceMetadata.get(theKey);
if (retValObj == null) {
return null;
} else if (retValObj instanceof String) {
if (StringUtils.isBlank((String) retValObj)) {
return null;
}
return new StringDt((String) retValObj);
} else if (retValObj instanceof StringDt) {
if (((StringDt) retValObj).isEmpty()) {
return null;
} else {
return (StringDt) retValObj;
}
}
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected "
+ InstantDt.class.getCanonicalName());
}
private static DecimalDt getDecimalFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum<?>, Object> theResourceMetadata, ResourceMetadataKeyEnum<DecimalDt> theKey) {
Object retValObj = theResourceMetadata.get(theKey);
if (retValObj == null) {
return null;
} else if (retValObj instanceof DecimalDt) {
if (((DecimalDt) retValObj).isEmpty()) {
return null;
} else {
return (DecimalDt) retValObj;
}
} else if (retValObj instanceof String) {
if (StringUtils.isBlank((String) retValObj)) {
return null;
}
return new DecimalDt((String) retValObj);
} else if (retValObj instanceof Double) {
return new DecimalDt((Double) retValObj);
}
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected "
+ InstantDt.class.getCanonicalName());
}
@SuppressWarnings("unchecked")
private static <T extends Enum<?>> T getEnumFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum<?>, Object> theResourceMetadata, ResourceMetadataKeyEnum<T> theKey, Class<T> theEnumType, IValueSetEnumBinder<T> theBinder) {
Object retValObj = theResourceMetadata.get(theKey);

View File

@ -481,31 +481,8 @@ public class IdDt implements IPrimitiveDatatype<String> {
* The resource name (e.g. "Patient")
* @return A fully qualified URL for this ID (e.g. "http://example.com/fhir/Patient/1")
*/
public String withServerBase(String theServerBase, String theResourceType) {
if (getValue().startsWith("http")) {
return getValue();
}
StringBuilder retVal = new StringBuilder();
retVal.append(theServerBase);
if (retVal.charAt(retVal.length() - 1) != '/') {
retVal.append('/');
}
if (isNotBlank(getResourceType())) {
retVal.append(getResourceType());
} else {
retVal.append(theResourceType);
}
retVal.append('/');
retVal.append(getIdPart());
if (hasVersionIdPart()) {
retVal.append('/');
retVal.append(Constants.PARAM_HISTORY);
retVal.append('/');
retVal.append(getVersionIdPart());
}
return retVal.toString();
public IdDt withServerBase(String theServerBase, String theResourceType) {
return new IdDt(theServerBase, theResourceType, getIdPart(), getVersionIdPart());
}
/**

View File

@ -1012,6 +1012,9 @@ class ParserState<T> {
if (!myEntry.getStatus().isEmpty()) {
ResourceMetadataKeyEnum.ENTRY_STATUS.put(myEntry.getResource(), myEntry.getStatus().getValueAsEnum());
}
if (!myEntry.getStatus().isEmpty()) {
ResourceMetadataKeyEnum.ENTRY_SCORE.put(myEntry.getResource(), myEntry.getScore());
}
}
}
@ -1114,12 +1117,17 @@ class ParserState<T> {
for (BundleEntry nextEntry : myInstance.getEntries()) {
IResource nextResource = nextEntry.getResource();
String baseUrl = myInstance.getLinkBase().getValue();
String bundleBaseUrl = myInstance.getLinkBase().getValue();
String entryBaseUrl = nextEntry.getLinkBase().getValue();
String version = ResourceMetadataKeyEnum.VERSION.get(nextResource);
String resourceName = myContext.getResourceDefinition(nextResource).getName();
String idPart = nextResource.getId().getIdPart();
if (isNotBlank(idPart)) {
nextResource.setId(new IdDt(baseUrl, resourceName, idPart, version));
String bundleIdPart = nextResource.getId().getIdPart();
if (isNotBlank(bundleIdPart)) {
if (isNotBlank(entryBaseUrl)) {
nextResource.setId(new IdDt(entryBaseUrl, resourceName, bundleIdPart, version));
} else {
nextResource.setId(new IdDt(bundleBaseUrl, resourceName, bundleIdPart, version));
}
}
}

View File

@ -275,7 +275,7 @@ public class XmlParser extends BaseParser implements IParser {
IResource nextResource = nextEntry.getResource();
if (nextResource.getId() != null && nextResource.getId().hasBaseUrl()) {
if (!nextResource.getId().getBaseUrl().equals(bundleBaseUrl)) {
writeOptionalTagWithValue(theEventWriter, "base", bundleBaseUrl);
writeOptionalTagWithValue(theEventWriter, "base", nextResource.getId().getBaseUrl());
}
}

View File

@ -47,10 +47,24 @@ public @interface IncludeParam {
* within the given set. If an _include parameter is passed to the server
* which does not match any allowed values the server will return an error.
* <p>
* You may also pass in a value of "*" which indicates to the server
* that any value is allowable and will be passed to this parameter. This is
* helpful if you want to explicitly declare support for some includes, but also
* allow others implicitly (e.g. imports from other resources)
* Values for this parameter takew the form that the FHIR specification
* defines for <code>_include</code> values, namely <code>[Resource Name].[path]</code>.
* For example: <code>"Patient.link.other"</code>
* or <code>"Encounter.partOf"</code>
* </p>
* <p>
* You may also pass in a value of "*" which indicates means that the
* client may request <code>_include=*</code>. This is a request to
* include all referenced resources as well as any resources referenced
* by those resources, etc.
* </p>
* <p>
* Leave this parameter empty if you do not want the server to declare or
* restrict which includes are allowable. In this case, the client may add
* any _include value they want, and that value will be accepted by the server
* and passed to the handling method. Note that this means that the server
* will not declare which _include values it supports in its conformance
* statement.
* </p>
*/
String[] allow() default {};

View File

@ -112,7 +112,7 @@ class IncludeParameter extends BaseQueryParameter {
}
@Override
public Object parse(List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException {
public Object parse(FhirContext theContext, List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException {
Collection<Include> retValCollection = null;
if (myInstantiableCollectionType != null) {
try {
@ -127,14 +127,15 @@ class IncludeParameter extends BaseQueryParameter {
continue;
}
if (nextParamList.size() > 1) {
throw new InvalidRequestException("'OR' query parameters (values containing ',') are not supported in _include parameters");
throw new InvalidRequestException(theContext.getLocalizer().getMessage(IncludeParameter.class, "orIncludeInRequest"));
}
String value = nextParamList.get(0);
if (myAllow != null) {
if (!myAllow.contains(value)) {
if (!myAllow.contains("*")) {
throw new InvalidRequestException("Invalid _include parameter value: '" + value + "'. Valid values are: " + new TreeSet<String>(myAllow));
String msg = theContext.getLocalizer().getMessage(IncludeParameter.class, "invalidIncludeNameInRequest", value, new TreeSet<String>(myAllow).toString());
throw new InvalidRequestException(msg);
}
}
}

View File

@ -213,7 +213,7 @@ public class SearchParameter extends BaseQueryParameter {
* @see ca.uhn.fhir.rest.param.IParameter#parse(java.util.List)
*/
@Override
public Object parse(List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException {
public Object parse(FhirContext theContext, List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException {
return myParamBinder.parse(getName(), theString);
}

View File

@ -42,21 +42,60 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public abstract class BaseQueryParameter implements IParameter {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseQueryParameter.class);
public abstract List<QualifiedParamList> encode(FhirContext theContext, Object theObject) throws InternalErrorException;
public abstract String getName();
public abstract Object parse(List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException;
public abstract boolean isRequired();
public abstract SearchParamTypeEnum getParamType();
/**
* Parameter should return true if {@link #parse(List)} should be called even if the query string contained no
* values for the given parameter
* Returns null if blacklist is "none"
*/
public Set<String> getQualifierBlacklist() {
return null;
}
/**
* Returns null if whitelist is "all"
*/
public Set<String> getQualifierWhitelist() {
return null;
}
/**
* Parameter should return true if {@link #parse(FhirContext, List)} should be called even if the query string
* contained no values for the given parameter
*/
public abstract boolean handlesMissing();
public abstract SearchParamTypeEnum getParamType();
@Override
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
// ignore for now
}
public abstract boolean isRequired();
public abstract Object parse(FhirContext theContext, List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException;
private void parseParams(RequestDetails theRequest, List<QualifiedParamList> paramList, String theQualifiedParamName, String theQualifier) {
QualifierDetails qualifiers = SearchMethodBinding.extractQualifiersFromParameterName(theQualifier);
if (!qualifiers.passes(getQualifierWhitelist(), getQualifierBlacklist())) {
return;
}
String[] value = theRequest.getParameters().get(theQualifiedParamName);
if (value != null) {
for (String nextParam : value) {
if (nextParam.contains(",") == false) {
paramList.add(QualifiedParamList.singleton(theQualifier, nextParam));
} else {
paramList.add(QualifiedParamList.splitQueryStringByCommasIgnoreEscape(theQualifier, nextParam));
}
}
}
}
@Override
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments) throws InternalErrorException {
@ -87,7 +126,7 @@ public abstract class BaseQueryParameter implements IParameter {
theTargetQueryArguments.put(getName() + StringUtils.defaultString(qualifier), paramValues);
}
}
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseQueryParameter.class);
@Override
public Object translateQueryParametersIntoServerArgument(Request theRequest, Object theRequestContents) throws InternalErrorException, InvalidRequestException {
@ -107,51 +146,14 @@ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger
ourLog.debug("No value for parameter '{}' - Qualified names {} and qualifier whitelist {}", getName(), qualified, getQualifierWhitelist());
if (handlesMissing()) {
return parse(paramList);
return parse(theRequest.getServer().getFhirContext(), paramList);
} else {
return null;
}
}
return parse(paramList);
return parse(theRequest.getServer().getFhirContext(), paramList);
}
private void parseParams(RequestDetails theRequest, List<QualifiedParamList> paramList, String theQualifiedParamName, String theQualifier) {
QualifierDetails qualifiers = SearchMethodBinding.extractQualifiersFromParameterName(theQualifier);
if (!qualifiers.passes(getQualifierWhitelist(), getQualifierBlacklist())) {
return;
}
String[] value = theRequest.getParameters().get(theQualifiedParamName);
if (value != null) {
for (String nextParam : value) {
if (nextParam.contains(",") == false) {
paramList.add(QualifiedParamList.singleton(theQualifier, nextParam));
} else {
paramList.add(QualifiedParamList.splitQueryStringByCommasIgnoreEscape(theQualifier, nextParam));
}
}
}
}
@Override
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
// ignore for now
}
/**
* Returns null if blacklist is "none"
*/
public Set<String> getQualifierBlacklist() {
return null;
}
/**
* Returns null if whitelist is "all"
*/
public Set<String> getQualifierWhitelist() {
return null;
}
}

View File

@ -1394,8 +1394,8 @@ public class RestfulServer extends HttpServlet {
if (theResource.getId() != null && theResource.getId().hasIdPart() && isNotBlank(theServerBase)) {
String resName = theServer.getFhirContext().getResourceDefinition(theResource).getName();
String fullId = theResource.getId().withServerBase(theServerBase, resName);
theHttpResponse.addHeader(Constants.HEADER_CONTENT_LOCATION, fullId);
IdDt fullId = theResource.getId().withServerBase(theServerBase, resName);
theHttpResponse.addHeader(Constants.HEADER_CONTENT_LOCATION, fullId.getValue());
}
if (theServer.getETagSupport() == ETagSupportEnum.ENABLED) {

View File

@ -8,6 +8,9 @@ ca.uhn.fhir.rest.client.GenericClient.noVersionIdForVread=No version specified i
ca.uhn.fhir.rest.client.GenericClient.incompleteUriForRead=The given URI is not an absolute URL and is not usable for this operation: {0}
ca.uhn.fhir.rest.client.GenericClient.cannotDetermineResourceTypeFromUri=Unable to determine the resource type from the given URI: {0}
ca.uhn.fhir.rest.method.IncludeParameter.invalidIncludeNameInRequest=Invalid _include parameter value: '{0}'. Valid values are: {1}
ca.uhn.fhir.rest.method.IncludeParameter.orIncludeInRequest='OR' query parameters (values containing ',') are not supported in _include parameters
ca.uhn.fhir.rest.method.SearchMethodBinding.invalidSpecialParamName=Method [{0}] in provider [{1}] contains search parameter annotated to use name [{2}] - This name is reserved according to the FHIR specification and can not be used as a search parameter name.
ca.uhn.fhir.rest.method.SearchMethodBinding.idWithoutCompartment=Method [{0}] in provider [{1}] has an @IdParam parameter. This is only allowable for compartment search (e.g. @Search(compartment="foo") )
ca.uhn.fhir.rest.method.SearchMethodBinding.idNullForCompartmentSearch=ID parameter can not be null or empty for compartment search

View File

@ -65,6 +65,8 @@ import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.base.composite.BaseIdentifierDt;
import ca.uhn.fhir.model.dstu.composite.CodingDt;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu.composite.QuantityDt;
@ -1353,14 +1355,14 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
TokenParam id = (TokenParam) theParameter;
system = id.getSystem();
code = id.getValue();
} else if (theParameter instanceof IdentifierDt) {
IdentifierDt id = (IdentifierDt) theParameter;
system = id.getSystem().getValueAsString();
code = id.getValue().getValue();
} else if (theParameter instanceof CodingDt) {
CodingDt id = (CodingDt) theParameter;
system = id.getSystem().getValueAsString();
code = id.getCode().getValue();
} else if (theParameter instanceof BaseIdentifierDt) {
BaseIdentifierDt id = (BaseIdentifierDt) theParameter;
system = id.getSystemElement().getValueAsString();
code = id.getValueElement().getValue();
} else if (theParameter instanceof BaseCodingDt) {
BaseCodingDt id = (BaseCodingDt) theParameter;
system = id.getSystemElement().getValueAsString();
code = id.getCodeElement().getValue();
} else {
throw new IllegalArgumentException("Invalid token type: " + theParameter.getClass());
}

View File

@ -350,7 +350,7 @@ class SearchParamExtractorDev implements ISearchParamExtractor {
}
} else if (nextObject instanceof ContactPointDt) {
ContactPointDt nextContact = (ContactPointDt) nextObject;
if (nextContact.getValue().isEmpty() == false) {
if (nextContact.getValueElement().isEmpty() == false) {
ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(resourceName, BaseFhirDao.normalizeString(nextContact.getValueElement().getValueAsString()), nextContact.getValue());
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
@ -415,7 +415,7 @@ class SearchParamExtractorDev implements ISearchParamExtractor {
codes.add(nextValue.getValueAsString());
} else if (nextObject instanceof CodeableConceptDt) {
CodeableConceptDt nextCC = (CodeableConceptDt) nextObject;
if (!nextCC.getText().isEmpty()) {
if (!nextCC.getTextElement().isEmpty()) {
ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(nextSpDef.getName(), BaseFhirDao.normalizeString(nextCC.getTextElement().getValue()), nextCC.getTextElement().getValue());
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
@ -433,7 +433,7 @@ class SearchParamExtractorDev implements ISearchParamExtractor {
codes.add(nextCode);
}
if (!nextCoding.getDisplay().isEmpty()) {
if (!nextCoding.getDisplayElement().isEmpty()) {
systems.add(null);
codes.add(nextCoding.getDisplayElement().getValue());
}

View File

@ -23,14 +23,15 @@ import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
import ca.uhn.fhir.model.dev.composite.IdentifierDt;
import ca.uhn.fhir.model.dev.composite.QuantityDt;
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu.resource.Device;
import ca.uhn.fhir.model.dstu.resource.DiagnosticReport;
import ca.uhn.fhir.model.dstu.resource.Location;
import ca.uhn.fhir.model.dstu.resource.Observation;
import ca.uhn.fhir.model.dstu.resource.Organization;
import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.model.dev.resource.Device;
import ca.uhn.fhir.model.dev.resource.DiagnosticReport;
import ca.uhn.fhir.model.dev.resource.Location;
import ca.uhn.fhir.model.dev.resource.Observation;
import ca.uhn.fhir.model.dev.resource.Organization;
import ca.uhn.fhir.model.dev.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.rest.api.MethodOutcome;
@ -49,6 +50,7 @@ public class FhirSystemDaoTest {
private static IFhirResourceDao<Location> ourLocationDao;
private static Date ourTestStarted;
private static IFhirSystemDao ourSystemDao;
private static FhirContext ourFhirContext;
@Test
public void testHistory() throws Exception {
@ -56,7 +58,7 @@ public class FhirSystemDaoTest {
Thread.sleep(10);
Patient patient = new Patient();
patient.addIdentifier("urn:system", "testHistory");
patient.addIdentifier().setSystem("urn:system").setValue( "testHistory");
patient.addName().addFamily("Tester").addGiven("Joe");
IdDt pid = ourPatientDao.create(patient).getId().toVersionless();
@ -104,7 +106,7 @@ public class FhirSystemDaoTest {
TagList tl1 = new TagList();
tl1.addTag("testGetAllTagsScheme1", "testGetAllTagsTerm1", "testGetAllTagsLabel1");
Patient p1 = new Patient();
p1.addIdentifier("foo", "testGetAllTags01");
p1.addIdentifier().setSystem("foo").setValue("testGetAllTags01");
ResourceMetadataKeyEnum.TAG_LIST.put(p1, tl1);
ourPatientDao.create(p1);
@ -175,7 +177,7 @@ public class FhirSystemDaoTest {
Patient p1 = new Patient();
p1.getId().setValue("testTransactionWithUpdateXXX01");
p1.addIdentifier("system", "testTransactionWithUpdate01");
p1.addIdentifier().setSystem("system").setValue("testTransactionWithUpdate01");
res.add(p1);
Observation p2 = new Observation();
@ -200,7 +202,7 @@ public class FhirSystemDaoTest {
p1.addName().addFamily("Name1");
p1.setId(p1.getId().toUnqualified().toVersionless());
p2.addReferenceRange().setHigh(123L);
p2.addReferenceRange().setHigh(new QuantityDt(123L));
p2.setId(p2.getId().toUnqualified().toVersionless());
ourSystemDao.transaction(res);
@ -221,7 +223,7 @@ public class FhirSystemDaoTest {
Patient p1 = new Patient();
p1.setId("cid:patient1");
p1.addIdentifier("system", "testTransactionWithCidIds01");
p1.addIdentifier().setSystem("system").setValue("testTransactionWithCidIds01");
res.add(p1);
Observation o1 = new Observation();
@ -251,7 +253,7 @@ public class FhirSystemDaoTest {
public void testTransactionFromBundle() throws Exception {
InputStream bundleRes = FhirSystemDaoTest.class.getResourceAsStream("/bundle.json");
Bundle bundle = new FhirContext().newJsonParser().parseBundle(new InputStreamReader(bundleRes));
Bundle bundle = ourFhirContext.newJsonParser().parseBundle(new InputStreamReader(bundleRes));
List<IResource> res = bundle.toListOfResources();
ourSystemDao.transaction(res);
@ -267,7 +269,7 @@ public class FhirSystemDaoTest {
public void testPersistWithSimpleLink() {
Patient patient = new Patient();
patient.setId(new IdDt("Patient/testPersistWithSimpleLinkP01"));
patient.addIdentifier("urn:system", "testPersistWithSimpleLinkP01");
patient.addIdentifier().setSystem("urn:system").setValue( "testPersistWithSimpleLinkP01");
patient.addName().addFamily("Tester").addGiven("Joe");
Observation obs = new Observation();
@ -302,7 +304,7 @@ public class FhirSystemDaoTest {
patient = (Patient) patResults.getResources(0,1).get(0);
obs = (Observation) obsResults.getResources(0, 1).get(0);
patient.addIdentifier("urn:system", "testPersistWithSimpleLinkP02");
patient.addIdentifier().setSystem("urn:system").setValue( "testPersistWithSimpleLinkP02");
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO02");
ourSystemDao.transaction(Arrays.asList((IResource) patient, obs));
@ -328,7 +330,7 @@ public class FhirSystemDaoTest {
Map<String, Long> oldCounts = ourSystemDao.getResourceCounts();
Patient patient = new Patient();
patient.addIdentifier("urn:system", "testGetResourceCountsP01");
patient.addIdentifier().setSystem("urn:system").setValue( "testGetResourceCountsP01");
patient.addName().addFamily("Tester").addGiven("Joe");
ourPatientDao.create(patient);
@ -378,6 +380,7 @@ public class FhirSystemDaoTest {
public static void beforeClass() {
ourTestStarted = new Date();
ourCtx = new ClassPathXmlApplicationContext("fhir-jpabase-spring-test-config.xml");
ourFhirContext = ourCtx.getBean(FhirContext.class);
ourPatientDao = ourCtx.getBean("myPatientDao", IFhirResourceDao.class);
ourObservationDao = ourCtx.getBean("myObservationDao", IFhirResourceDao.class);
ourDiagnosticReportDao = ourCtx.getBean("myDiagnosticReportDao", IFhirResourceDao.class);

View File

@ -4,18 +4,12 @@
"entry":[
{
"deleted":null,
"title":"Patient http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.0/Patient/5556918",
"id":"Patient/5556918",
"link":[
{
"rel":"self",
"href":"Patient/5556918"
}
],
"published":"2014-05-29T10:49:32-04:00",
"content":{
"resource":{
"resourceType":"Patient",
"id":"http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.0/Patient/5556918",
"id":"5556918",
"meta":{
"lastUpdated":"2014-05-29T10:49:32-04:00"
},
"text":{
"status":"generated",
"div":"<div xmlns=\"http://www.w3.org/1999/xhtml\"><div class=\"hapiHeaderText\"> Donald null <b>DUCK </b></div><table class=\"hapiPropertyTable\"><tbody><tr><td>Identifier</td><td>7000135</td></tr><tr><td>Address</td><td><span>10 Duxon Street </span><br/><span>VICTORIA </span><span>BC </span><span>Can </span></td></tr><tr><td>Date of birth</td><td><span>01 June 1980</span></td></tr></tbody></table></div>"
@ -59,14 +53,7 @@
"use":"home"
}
],
"gender":{
"coding":[
{
"system":"http://hl7.org/fhir/v3/AdministrativeGender",
"code":"M"
}
]
},
"gender":"M",
"birthDate":"1980-06-01T00:00:00",
"address":[
{
@ -87,18 +74,12 @@
},
{
"deleted":null,
"title":"DiagnosticReport http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.0/DiagnosticReport/5978827",
"id":"DiagnosticReport/5978827",
"link":[
{
"rel":"self",
"href":"DiagnosticReport/5978827"
}
],
"published":"2014-05-29T10:49:33-04:00",
"content":{
"resource":{
"id":"5978827",
"resourceType":"DiagnosticReport",
"id":"http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.0/DiagnosticReport/5978827",
"meta":{
"lastUpdated":"2014-05-29T10:49:32-04:00"
},
"text":{
"status":"generated",
"div":"<div xmlns=\"http://www.w3.org/1999/xhtml\"><div class=\"hapiHeaderText\"> C&amp;S </div><table class=\"hapiPropertyTable\"><tbody><tr><td>Status</td><td>partial</td></tr><tr><td>Issued</td><td> 29 April 2014 17:21:56 </td></tr></tbody></table><table class=\"hapiTableOfValues\"><thead><tr><td>Name</td><td>Value</td><td>Interpretation</td><td>Reference Range</td><td>Status</td></tr></thead><tbody><tr class=\"hapiTableOfValuesRowEven\"><td> Collection Info </td><td> Spec #102758: 26 Sep 08 1117</td><td/><td/><td>preliminary</td></tr><tr class=\"hapiTableOfValuesRowOdd\"><td> Direct Stain </td><td> pus cells</td><td/><td/><td>preliminary</td></tr><tr class=\"hapiTableOfValuesRowEven\"><td> Header </td><td> To view Culture &amp; Sensitivity Results, select</td><td/><td/><td/></tr><tr class=\"hapiTableOfValuesRowOdd\"><td> Header </td><td> (Y) Report Query. Do NOT select number beside</td><td/><td/><td/></tr><tr class=\"hapiTableOfValuesRowEven\"><td> Header </td><td> Prelim or Final Result field, as there is</td><td/><td/><td/></tr><tr class=\"hapiTableOfValuesRowOdd\"><td> Header </td><td> potential for viewing an incomplete report.</td><td/><td/><td/></tr><tr class=\"hapiTableOfValuesRowEven\"><td> Organism </td><td> Haemophilus influenzae</td><td/><td/><td>final</td></tr><tr class=\"hapiTableOfValuesRowOdd\"><td> Qualifier </td><td> =>10 x E6 cfu/L SIGNIFICANT RESULT. Organisms cultured in quantities =>10 x E6 cfu/L are consistent with pneumonia. beta-lactamase positive result suggests resistance to ampicillin but generally susceptible to amoxicillin- clavulanic and cefuroxime.</td><td/><td/><td>final</td></tr><tr class=\"hapiTableOfValuesRowEven\"><td> Sensitivities </td><td> _Beta-lactamase Pos: </td><td/><td/><td>final</td></tr><tr class=\"hapiTableOfValuesRowOdd\"><td> Test Comment </td><td> =>10 x E6 cfu/L Commensal flora</td><td/><td/><td>final</td></tr></tbody></table></div>"
@ -555,18 +536,12 @@
},
{
"deleted":null,
"title":"Organization http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.0/Organization/1.3.6.1.4.1.12201",
"id":"Organization/1.3.6.1.4.1.12201",
"link":[
{
"rel":"self",
"href":"Organization/1.3.6.1.4.1.12201"
}
],
"published":"2014-05-29T10:49:32-04:00",
"content":{
"resource":{
"resourceType":"Organization",
"id":"http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.0/Organization/1.3.6.1.4.1.12201",
"id":"1.3.6.1.4.1.12201",
"meta":{
"lastUpdated":"2014-05-29T10:49:32-04:00"
},
"extension":[
{
"url":"http://fhir.connectinggta.ca/Profile/organization#providerIdPool",

View File

@ -13,7 +13,7 @@
<context:annotation-config />
<context:mbean-server />
<bean id="myFhirContext" class="ca.uhn.fhir.context.FhirContext"></bean>
<bean id="myFhirContext" class="ca.uhn.fhir.context.FhirContext" factory-method="forDstu2"></bean>
<bean id="myDaoConfig" class="ca.uhn.fhir.jpa.dao.DaoConfig">
</bean>
@ -23,35 +23,35 @@
</bean>
<bean id="myDiagnosticReportDao" class="ca.uhn.fhir.jpa.dao.FhirResourceDao">
<property name="resourceType" value="ca.uhn.fhir.model.dstu.resource.DiagnosticReport"/>
<property name="resourceType" value="ca.uhn.fhir.model.dev.resource.DiagnosticReport"/>
<property name="context" ref="myFhirContext"/>
</bean>
<bean id="myDeviceDao" class="ca.uhn.fhir.jpa.dao.FhirResourceDao">
<property name="resourceType" value="ca.uhn.fhir.model.dstu.resource.Device"/>
<property name="resourceType" value="ca.uhn.fhir.model.dev.resource.Device"/>
<property name="context" ref="myFhirContext"/>
</bean>
<bean id="myPatientDao" class="ca.uhn.fhir.jpa.dao.FhirResourceDao">
<property name="resourceType" value="ca.uhn.fhir.model.dstu.resource.Patient"/>
<property name="resourceType" value="ca.uhn.fhir.model.dev.resource.Patient"/>
<property name="context" ref="myFhirContext"/>
</bean>
<bean id="myObservationDao" class="ca.uhn.fhir.jpa.dao.FhirResourceDao">
<property name="resourceType" value="ca.uhn.fhir.model.dstu.resource.Observation"/>
<property name="resourceType" value="ca.uhn.fhir.model.dev.resource.Observation"/>
<property name="context" ref="myFhirContext"/>
</bean>
<bean id="myOrganizationDao" class="ca.uhn.fhir.jpa.dao.FhirResourceDao">
<property name="resourceType" value="ca.uhn.fhir.model.dstu.resource.Organization"/>
<property name="resourceType" value="ca.uhn.fhir.model.dev.resource.Organization"/>
<property name="context" ref="myFhirContext"/>
</bean>
<bean id="myLocationDao" class="ca.uhn.fhir.jpa.dao.FhirResourceDao">
<property name="resourceType" value="ca.uhn.fhir.model.dstu.resource.Location"/>
<property name="resourceType" value="ca.uhn.fhir.model.dev.resource.Location"/>
<property name="context" ref="myFhirContext"/>
</bean>
<bean id="myQuestionnaireDao" class="ca.uhn.fhir.jpa.dao.FhirResourceDao">
<property name="resourceType" value="ca.uhn.fhir.model.dstu.resource.Questionnaire"/>
<property name="resourceType" value="ca.uhn.fhir.model.dev.resource.Questionnaire"/>
<property name="context" ref="myFhirContext"/>
</bean>
<bean id="myEncounterDao" class="ca.uhn.fhir.jpa.dao.FhirResourceDao">
<property name="resourceType" value="ca.uhn.fhir.model.dstu.resource.Encounter"/>
<property name="resourceType" value="ca.uhn.fhir.model.dev.resource.Encounter"/>
<property name="context" ref="myFhirContext"/>
</bean>

View File

@ -3,6 +3,7 @@ package ca.uhn.fhir.parser;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.io.IOException;
import java.io.StringReader;
import org.apache.commons.io.IOUtils;
@ -10,6 +11,7 @@ import org.custommonkey.xmlunit.Diff;
import org.custommonkey.xmlunit.XMLUnit;
import org.junit.BeforeClass;
import org.junit.Test;
import org.xml.sax.SAXException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
@ -18,6 +20,7 @@ import ca.uhn.fhir.model.dev.composite.DurationDt;
import ca.uhn.fhir.model.dev.resource.Encounter;
import ca.uhn.fhir.model.dev.resource.MedicationPrescription;
import ca.uhn.fhir.model.dev.resource.Organization;
import ca.uhn.fhir.model.dev.resource.Patient;
import ca.uhn.fhir.model.dstu.resource.Binary;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleEntryStatusEnum;
@ -132,4 +135,59 @@ public class XmlParserTest {
}
@Test
public void testParseMetadata() throws Exception {
//@formatter:off
String bundle = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
" <base value=\"http://foo/fhirBase1\"/>\n" +
" <total value=\"1\"/>\n" +
" <link>\n" +
" <relation value=\"self\"/>\n" +
" <url value=\"http://localhost:52788/Binary?_pretty=true\"/>\n" +
" </link>\n" +
" <entry>\n" +
" <base value=\"http://foo/fhirBase2\"/>\n" +
" <status value=\"match\"/>\n" +
" <search value=\"http://foo/Patient?identifier=value\"/>\n" +
" <score value=\"0.123\"/>\n" +
" <resource>\n" +
" <Patient xmlns=\"http://hl7.org/fhir\">\n" +
" <id value=\"1\"/>\n" +
" <meta>\n" +
" <versionId value=\"2\"/>\n" +
" <lastUpdated value=\"2001-02-22T11:22:33-05:00\"/>\n" +
" </meta>\n" +
" <birthDate value=\"2012-01-02\"/>\n" +
" </Patient>\n" +
" </resource>\n" +
" </entry>\n" +
"</Bundle>";
//@formatter:on
Bundle b = ourCtx.newXmlParser().parseBundle(bundle);
assertEquals(1, b.getEntries().size());
Patient pt = (Patient) b.getEntries().get(0).getResource();
assertEquals("http://foo/fhirBase2/Patient/1/_history/2", pt.getId().getValue());
assertEquals("2012-01-02", pt.getBirthDateElement().getValueAsString());
assertEquals("0.123", ResourceMetadataKeyEnum.ENTRY_SCORE.get(pt).getValueAsString());
assertEquals("match", ResourceMetadataKeyEnum.ENTRY_STATUS.get(pt).getCode());
assertEquals("http://foo/Patient?identifier=value", ResourceMetadataKeyEnum.LINK_SEARCH.get(pt));
assertEquals("2001-02-22T11:22:33-05:00", ResourceMetadataKeyEnum.UPDATED.get(pt).getValueAsString());
Bundle toBundle = new Bundle();
toBundle.getLinkBase().setValue("http://foo/fhirBase1");
toBundle.getTotalResults().setValue(1);
toBundle.getLinkSelf().setValue("http://localhost:52788/Binary?_pretty=true");
toBundle.addResource(pt, ourCtx, "http://foo/fhirBase1");
String reEncoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(toBundle);
ourLog.info(reEncoded);
Diff d = new Diff(new StringReader(bundle), new StringReader(reEncoded));
assertTrue(d.toString(), d.identical());
}
}

View File

@ -1,6 +1,6 @@
package ca.uhn.fhir.rest.server;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.util.ArrayList;
@ -86,7 +86,7 @@ public class IncludeTest {
Patient p = bundle.getResources(Patient.class).get(0);
assertEquals(1, p.getName().size());
assertEquals("Hello", p.getId().getIdPart());
assertEquals("foo", p.getName().get(0).getFamilyFirstRep().getValue());
assertEquals("Patient.foo", p.getName().get(0).getFamilyFirstRep().getValue());
}
@ -240,6 +240,11 @@ public class IncludeTest {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello&_include=foo&_include=baz");
HttpResponse status = ourClient.execute(httpGet);
assertEquals(400, status.getStatusLine().getStatusCode());
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertThat(responseContent,containsString("Invalid _include parameter value"));
}
@AfterClass
@ -436,11 +441,13 @@ public class IncludeTest {
}
@Search
public List<Patient> findPatient(@RequiredParam(name = Patient.SP_NAME) StringDt theName, @IncludeParam(allow = { "foo", "bar" }) Set<Include> theIncludes) {
public List<Patient> findPatientWithSimpleNames(
@RequiredParam(name = Patient.SP_NAME) StringDt theName,
@IncludeParam(allow = { "foo", "bar" }) Set<Include> theIncludes) {
ArrayList<Patient> retVal = new ArrayList<Patient>();
Patient p = new Patient();
p.addIdentifier("foo", "bar");
p.addIdentifier("Mr", "Test");
p.setId(theName.getValue());

View File

@ -56,6 +56,14 @@
value of
<![CDATA[<code>*</code>]]>. Thanks to Bill de Beaubien for reporting!
</action>
<action type="fix">
IdDt method
<![CDATA[withServerBase]]>
returned String (unlike all of the other "withFoo" methods on that class),
and did not work correctly if the IdDt already had a server base. This
has been corrected. Note that the return type for this method has been
changed, so code may need to be updated.
</action>
</release>
<release version="0.8" date="2014-Dec-17">
<action type="add">