Support $validate operation correctly in DSTU2 clients and in testpage
overlay
This commit is contained in:
parent
81bfc28147
commit
6f7ef96b97
|
@ -283,6 +283,11 @@ public class IdDt extends UriDt implements IPrimitiveDatatype<String>, IIdType {
|
|||
@Override
|
||||
public String getValue() {
|
||||
if (super.getValue() == null && myHaveComponentParts) {
|
||||
|
||||
if (determineLocalPrefix(myBaseUrl) != null && myResourceType == null && myUnqualifiedVersionId == null) {
|
||||
return myBaseUrl + myUnqualifiedId;
|
||||
}
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
if (isNotBlank(myBaseUrl)) {
|
||||
b.append(myBaseUrl);
|
||||
|
@ -395,11 +400,15 @@ public class IdDt extends UriDt implements IPrimitiveDatatype<String>, IIdType {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the ID is a local reference (in other words, it begins with the '#' character)
|
||||
* Returns <code>true</code> if the ID is a local reference (in other words, it begins with the '#' character
|
||||
* or it begins with "cid:" or "urn:")
|
||||
*/
|
||||
@Override
|
||||
public boolean isLocal() {
|
||||
return myUnqualifiedId != null && myUnqualifiedId.isEmpty() == false && myUnqualifiedId.charAt(0) == '#';
|
||||
if (myBaseUrl == null) {
|
||||
return false;
|
||||
}
|
||||
return "#".equals(myBaseUrl) || myBaseUrl.equals("cid:") || myBaseUrl.startsWith("urn:");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -410,6 +419,34 @@ public class IdDt extends UriDt implements IPrimitiveDatatype<String>, IIdType {
|
|||
setValue(theId.getValue());
|
||||
}
|
||||
|
||||
private String determineLocalPrefix(String theValue) {
|
||||
if (theValue == null || theValue.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (theValue.startsWith("#")) {
|
||||
return "#";
|
||||
}
|
||||
int lastPrefix = -1;
|
||||
for (int i = 0; i < theValue.length(); i++) {
|
||||
char nextChar = theValue.charAt(i);
|
||||
if (nextChar == ':') {
|
||||
lastPrefix = i;
|
||||
} else if (!Character.isLetter(nextChar) || !Character.isLowerCase(nextChar)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lastPrefix != -1) {
|
||||
String candidate = theValue.substring(0, lastPrefix + 1);
|
||||
if (candidate.startsWith("cid:") || candidate.startsWith("urn:")) {
|
||||
return candidate;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value
|
||||
*
|
||||
|
@ -426,15 +463,25 @@ public class IdDt extends UriDt implements IPrimitiveDatatype<String>, IIdType {
|
|||
// TODO: add validation
|
||||
super.setValue(theValue);
|
||||
myHaveComponentParts = false;
|
||||
|
||||
String localPrefix = determineLocalPrefix(theValue);
|
||||
|
||||
if (StringUtils.isBlank(theValue)) {
|
||||
myBaseUrl = null;
|
||||
super.setValue(null);
|
||||
myUnqualifiedId = null;
|
||||
myUnqualifiedVersionId = null;
|
||||
myResourceType = null;
|
||||
} else if (theValue.charAt(0) == '#') {
|
||||
} else if (theValue.charAt(0) == '#' && theValue.length() > 1) {
|
||||
super.setValue(theValue);
|
||||
myUnqualifiedId = theValue;
|
||||
myBaseUrl = "#";
|
||||
myUnqualifiedId = theValue.substring(1);
|
||||
myUnqualifiedVersionId = null;
|
||||
myResourceType = null;
|
||||
myHaveComponentParts = true;
|
||||
} else if (localPrefix != null) {
|
||||
myBaseUrl = localPrefix;
|
||||
myUnqualifiedId = theValue.substring(localPrefix.length());
|
||||
myUnqualifiedVersionId = null;
|
||||
myResourceType = null;
|
||||
myHaveComponentParts = true;
|
||||
|
|
|
@ -186,7 +186,7 @@ public abstract class BaseClient implements IRestfulClient {
|
|||
encoding=theEncoding;
|
||||
}
|
||||
|
||||
httpRequest = clientInvocation.asHttpRequest(myUrlBase, params, encoding);
|
||||
httpRequest = clientInvocation.asHttpRequest(myUrlBase, params, encoding, thePrettyPrint);
|
||||
|
||||
if (theLogRequestAndResponse) {
|
||||
ourLog.info("Client invoking: {}", httpRequest);
|
||||
|
|
|
@ -56,7 +56,7 @@ public abstract class BaseHttpClientInvocation {
|
|||
* The encoding to use for any serialized content sent to the
|
||||
* server
|
||||
*/
|
||||
public abstract HttpRequestBase asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding);
|
||||
public abstract HttpRequestBase asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding, Boolean thePrettyPrint);
|
||||
|
||||
protected static void appendExtraParamsWithQuestionMark(Map<String, List<String>> theExtraParams, StringBuilder theUrlBuilder, boolean theWithQuestionMark) {
|
||||
if (theExtraParams == null) {
|
||||
|
|
|
@ -158,7 +158,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
|
||||
HttpGetClientInvocation invocation = MethodUtil.createConformanceInvocation();
|
||||
if (isKeepResponses()) {
|
||||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding());
|
||||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -178,7 +178,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
public MethodOutcome create(IResource theResource) {
|
||||
BaseHttpClientInvocation invocation = MethodUtil.createCreateInvocation(theResource, myContext);
|
||||
if (isKeepResponses()) {
|
||||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding());
|
||||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint());
|
||||
}
|
||||
|
||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
|
||||
|
@ -200,7 +200,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
public MethodOutcome delete(final Class<? extends IResource> theType, IdDt theId) {
|
||||
HttpDeleteClientInvocation invocation = DeleteMethodBinding.createDeleteInvocation(theId.withResourceType(toResourceName(theType)));
|
||||
if (isKeepResponses()) {
|
||||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding());
|
||||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint());
|
||||
}
|
||||
|
||||
final String resourceName = myContext.getResourceDefinition(theType).getName();
|
||||
|
@ -236,7 +236,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
}
|
||||
}
|
||||
if (isKeepResponses()) {
|
||||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding());
|
||||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint());
|
||||
}
|
||||
|
||||
if (theIfVersionMatches != null) {
|
||||
|
@ -312,7 +312,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
String id = theIdDt != null && theIdDt.isEmpty() == false ? theIdDt.getValue() : null;
|
||||
HttpGetClientInvocation invocation = HistoryMethodBinding.createHistoryInvocation(resourceName, id, theSince, theLimit);
|
||||
if (isKeepResponses()) {
|
||||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding());
|
||||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint());
|
||||
}
|
||||
|
||||
BundleResponseHandler binding = new BundleResponseHandler(theType);
|
||||
|
@ -430,7 +430,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
|
||||
BaseHttpClientInvocation invocation = SearchMethodBinding.createSearchInvocation(myContext, toResourceName(theType), params, null, null, null);
|
||||
if (isKeepResponses()) {
|
||||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding());
|
||||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint());
|
||||
}
|
||||
|
||||
BundleResponseHandler binding = new BundleResponseHandler(theType);
|
||||
|
@ -474,7 +474,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
public List<IBaseResource> transaction(List<IBaseResource> theResources) {
|
||||
BaseHttpClientInvocation invocation = TransactionMethodBinding.createTransactionInvocation(theResources, myContext);
|
||||
if (isKeepResponses()) {
|
||||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding());
|
||||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint());
|
||||
}
|
||||
|
||||
Bundle resp = invokeClient(myContext, new BundleResponseHandler(null), invocation, myLogRequestAndResponse);
|
||||
|
@ -491,7 +491,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
public MethodOutcome update(IdDt theIdDt, IResource theResource) {
|
||||
BaseHttpClientInvocation invocation = MethodUtil.createUpdateInvocation(theResource, null, theIdDt, myContext);
|
||||
if (isKeepResponses()) {
|
||||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding());
|
||||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint());
|
||||
}
|
||||
|
||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
|
||||
|
@ -522,7 +522,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
}
|
||||
|
||||
if (isKeepResponses()) {
|
||||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding());
|
||||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint());
|
||||
}
|
||||
|
||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
|
||||
|
@ -601,7 +601,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
// }
|
||||
|
||||
if (isKeepResponses()) {
|
||||
myLastRequest = theInvocation.asHttpRequest(getServerBase(), theParams, getEncoding());
|
||||
myLastRequest = theInvocation.asHttpRequest(getServerBase(), theParams, getEncoding(), myPrettyPrint);
|
||||
}
|
||||
|
||||
Z resp = invokeClient(myContext, theHandler, theInvocation, myParamEncoding, myPrettyPrint, myQueryLogRequestAndResponse || myLogRequestAndResponse);
|
||||
|
|
|
@ -188,7 +188,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
|
|||
}
|
||||
|
||||
@Override
|
||||
public HttpRequestBase asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding) throws DataFormatException {
|
||||
public HttpRequestBase asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding, Boolean thePrettyPrint) throws DataFormatException {
|
||||
StringBuilder url = new StringBuilder();
|
||||
|
||||
if (myUrlPath == null) {
|
||||
|
@ -236,6 +236,10 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
|
|||
parser = myContext.newXmlParser();
|
||||
}
|
||||
|
||||
if (thePrettyPrint != null) {
|
||||
parser.setPrettyPrint(thePrettyPrint);
|
||||
}
|
||||
|
||||
parser.setOmitResourceId(myOmitResourceId);
|
||||
|
||||
AbstractHttpEntity entity;
|
||||
|
|
|
@ -50,7 +50,7 @@ public class HttpDeleteClientInvocation extends BaseHttpClientInvocation {
|
|||
}
|
||||
|
||||
@Override
|
||||
public HttpRequestBase asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding) {
|
||||
public HttpRequestBase asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding, Boolean thePrettyPrint) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(theUrlBase);
|
||||
if (!theUrlBase.endsWith("/")) {
|
||||
|
|
|
@ -79,7 +79,7 @@ public class HttpGetClientInvocation extends BaseHttpClientInvocation {
|
|||
}
|
||||
|
||||
@Override
|
||||
public HttpGet asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding) {
|
||||
public HttpGet asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding, Boolean thePrettyPrint) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
|
||||
if (!myUrlPath.contains("://")) {
|
||||
|
|
|
@ -38,7 +38,7 @@ public class HttpSimpleGetClientInvocation extends BaseHttpClientInvocation {
|
|||
}
|
||||
|
||||
@Override
|
||||
public HttpRequestBase asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding) {
|
||||
public HttpRequestBase asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding, Boolean thePrettyPrint) {
|
||||
HttpGet retVal = new HttpGet(myUrl);
|
||||
super.addHeadersToRequest(retVal);
|
||||
return retVal;
|
||||
|
|
|
@ -85,7 +85,11 @@ public class ReferenceParam extends IdDt implements IQueryParameterType {
|
|||
if (myBase.getMissing()!=null) {
|
||||
return myBase.getValueAsQueryToken();
|
||||
}
|
||||
return getIdPart();
|
||||
if (isLocal()) {
|
||||
return getValue();
|
||||
} else {
|
||||
return getIdPart();
|
||||
}
|
||||
}
|
||||
|
||||
public void setChain(String theChain) {
|
||||
|
|
|
@ -1048,8 +1048,8 @@ public abstract class BaseFhirDao implements IDao {
|
|||
quantityParams = extractSearchParamQuantity(entity, theResource);
|
||||
dateParams = extractSearchParamDates(entity, theResource);
|
||||
|
||||
ourLog.info("Indexing resource: {}", entity.getId());
|
||||
ourLog.info("Storing string indexes: {}", stringParams);
|
||||
// ourLog.info("Indexing resource: {}", entity.getId());
|
||||
ourLog.trace("Storing string indexes: {}", stringParams);
|
||||
|
||||
tokenParams = new ArrayList<ResourceIndexedSearchParamToken>();
|
||||
for (BaseResourceIndexedSearchParam next : extractSearchParamTokens(entity, theResource)) {
|
||||
|
|
|
@ -574,12 +574,12 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
|
|||
ReferenceParam ref = (ReferenceParam) params;
|
||||
|
||||
String resourceId = ref.getValueAsQueryToken();
|
||||
if (resourceId.contains("/")) {
|
||||
IdDt dt = new IdDt(resourceId);
|
||||
resourceId = dt.getIdPart();
|
||||
}
|
||||
|
||||
if (isBlank(ref.getChain())) {
|
||||
if (resourceId.contains("/")) {
|
||||
IdDt dt = new IdDt(resourceId);
|
||||
resourceId = dt.getIdPart();
|
||||
}
|
||||
Long targetPid = translateForcedIdToPid(new IdDt(resourceId));
|
||||
ourLog.info("Searching for resource link with target PID: {}", targetPid);
|
||||
Predicate eq = builder.equal(from.get("myTargetResourcePid"), targetPid);
|
||||
|
@ -1097,6 +1097,9 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
|
|||
|
||||
private DaoMethodOutcome doCreate(T theResource, String theIfNoneExist, boolean thePerformIndexing) {
|
||||
StopWatch w = new StopWatch();
|
||||
|
||||
preProcessResourceForStorage(theResource);
|
||||
|
||||
ResourceTable entity = new ResourceTable();
|
||||
entity.setResourceType(toResourceName(theResource));
|
||||
|
||||
|
@ -1112,7 +1115,7 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
|
|||
}
|
||||
}
|
||||
|
||||
if (theResource.getId().isEmpty() == false) {
|
||||
if (isNotBlank(theResource.getId().getIdPart())) {
|
||||
if (isValidPid(theResource.getId())) {
|
||||
throw new UnprocessableEntityException(
|
||||
"This server cannot create an entity with a user-specified numeric ID - Client should not specify an ID when creating a new resource, or should include at least one letter in the ID to force a client-defined ID");
|
||||
|
@ -1139,6 +1142,10 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
|
|||
return outcome;
|
||||
}
|
||||
|
||||
protected void preProcessResourceForStorage(T theResource) {
|
||||
// nothing by default
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagList getAllResourceTags() {
|
||||
StopWatch w = new StopWatch();
|
||||
|
@ -1995,6 +2002,8 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
|
|||
public DaoMethodOutcome update(T theResource, String theMatchUrl, boolean thePerformIndexing) {
|
||||
StopWatch w = new StopWatch();
|
||||
|
||||
preProcessResourceForStorage(theResource);
|
||||
|
||||
final ResourceTable entity;
|
||||
|
||||
IdDt resourceId;
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package ca.uhn.fhir.jpa.dao;
|
||||
|
||||
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||
import ca.uhn.fhir.model.dstu2.valueset.BundleTypeEnum;
|
||||
import ca.uhn.fhir.model.primitive.UriDt;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
|
||||
public class FhirBundleResourceDaoDstu2 extends FhirResourceDaoDstu2<Bundle> {
|
||||
|
||||
@Override
|
||||
protected void preProcessResourceForStorage(Bundle theResource) {
|
||||
super.preProcessResourceForStorage(theResource);
|
||||
|
||||
if (theResource.getTypeElement().getValueAsEnum() != BundleTypeEnum.DOCUMENT) {
|
||||
String message = "Unable to store a Bundle resource on this server with a Bundle.type value other than '" + BundleTypeEnum.DOCUMENT.getCode() + "' - Value was: " + (theResource.getTypeElement().getValueAsEnum() != null ? theResource.getTypeElement().getValueAsEnum().getCode() : "(missing)");
|
||||
throw new UnprocessableEntityException(message);
|
||||
}
|
||||
|
||||
theResource.setBase((UriDt)null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -60,14 +60,18 @@ public class FhirSystemDaoDstu1 extends BaseFhirSystemDao<List<IResource>> {
|
|||
|
||||
for (int i = 0; i < theResources.size(); i++) {
|
||||
IResource res = theResources.get(i);
|
||||
if (res.getId().hasIdPart() && !res.getId().hasResourceType()) {
|
||||
if (res.getId().hasIdPart() && !res.getId().hasResourceType() && !res.getId().isLocal()) {
|
||||
res.setId(new IdDt(toResourceName(res.getClass()), res.getId().getIdPart()));
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure that the bundle doesn't have any duplicates, since this causes all kinds of weirdness
|
||||
*/
|
||||
if (res.getId().hasResourceType() && res.getId().hasIdPart()) {
|
||||
if (res.getId().isLocal()) {
|
||||
if (!allIds.add(res.getId())) {
|
||||
throw new InvalidRequestException("Transaction bundle contains multiple resources with ID: " + res.getId());
|
||||
}
|
||||
} else if (res.getId().hasResourceType() && res.getId().hasIdPart()) {
|
||||
IdDt nextId = res.getId().toUnqualifiedVersionless();
|
||||
if (!allIds.add(nextId)) {
|
||||
throw new InvalidRequestException("Transaction bundle contains multiple resources with ID: " + nextId);
|
||||
|
@ -134,7 +138,7 @@ public class FhirSystemDaoDstu1 extends BaseFhirSystemDao<List<IResource>> {
|
|||
} else {
|
||||
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseFhirSystemDao.class, "transactionOperationWithMultipleMatchFailure", nextResouceOperationIn.name(), matchUrl, candidateMatches.size()));
|
||||
}
|
||||
} else if (nextId.isEmpty()) {
|
||||
} else if (nextId.isEmpty() || nextId.isLocal()) {
|
||||
entity = null;
|
||||
} else {
|
||||
entity = tryToLoadEntity(nextId);
|
||||
|
@ -144,7 +148,7 @@ public class FhirSystemDaoDstu1 extends BaseFhirSystemDao<List<IResource>> {
|
|||
if (entity == null) {
|
||||
nextResouceOperationOut = BundleEntryTransactionMethodEnum.POST;
|
||||
entity = toEntity(nextResource);
|
||||
if (nextId.isEmpty() == false && nextId.getIdPart().startsWith("cid:")) {
|
||||
if (nextId.isEmpty() == false && "cid:".equals(nextId.getBaseUrl())) {
|
||||
ourLog.debug("Resource in transaction has ID[{}], will replace with server assigned ID", nextId.getIdPart());
|
||||
} else if (nextResouceOperationIn == BundleEntryTransactionMethodEnum.POST) {
|
||||
if (nextId.isEmpty() == false) {
|
||||
|
@ -209,11 +213,11 @@ public class FhirSystemDaoDstu1 extends BaseFhirSystemDao<List<IResource>> {
|
|||
if (nextId.toUnqualifiedVersionless().equals(newId)) {
|
||||
ourLog.info("Transaction resource ID[{}] is being updated", newId);
|
||||
} else {
|
||||
if (!nextId.getIdPart().startsWith("#")) {
|
||||
nextId = new IdDt(resourceName, nextId.getIdPart());
|
||||
if (nextId.isLocal()) {
|
||||
// nextId = new IdDt(resourceName, nextId.getIdPart());
|
||||
ourLog.info("Transaction resource ID[{}] has been assigned new ID[{}]", nextId, newId);
|
||||
idConversions.put(nextId, newId);
|
||||
idConversions.put(new IdDt(nextId.getIdPart()), newId);
|
||||
idConversions.put(new IdDt(resourceName + "/" + nextId.getValue()), newId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -151,7 +151,7 @@ public class FhirSystemDaoDstu2 extends BaseFhirSystemDao<Bundle> {
|
|||
if (res != null) {
|
||||
|
||||
nextResourceId = res.getId();
|
||||
if (nextResourceId.hasIdPart() && !nextResourceId.hasResourceType()) {
|
||||
if (nextResourceId.hasIdPart() && !nextResourceId.hasResourceType() && !nextResourceId.isLocal()) {
|
||||
nextResourceId = new IdDt(toResourceName(res.getClass()), nextResourceId.getIdPart());
|
||||
res.setId(nextResourceId);
|
||||
}
|
||||
|
@ -159,7 +159,11 @@ public class FhirSystemDaoDstu2 extends BaseFhirSystemDao<Bundle> {
|
|||
/*
|
||||
* Ensure that the bundle doesn't have any duplicates, since this causes all kinds of weirdness
|
||||
*/
|
||||
if (nextResourceId.hasResourceType() && nextResourceId.hasIdPart()) {
|
||||
if (nextResourceId.isLocal()) {
|
||||
if (!allIds.add(nextResourceId)) {
|
||||
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseFhirSystemDao.class, "transactionContainsMultipleWithDuplicateId", nextResourceId));
|
||||
}
|
||||
} else if (nextResourceId.hasResourceType() && nextResourceId.hasIdPart()) {
|
||||
IdDt nextId = nextResourceId.toUnqualifiedVersionless();
|
||||
if (!allIds.add(nextId)) {
|
||||
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseFhirSystemDao.class, "transactionContainsMultipleWithDuplicateId", nextId));
|
||||
|
@ -173,6 +177,8 @@ public class FhirSystemDaoDstu2 extends BaseFhirSystemDao<Bundle> {
|
|||
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseFhirSystemDao.class, "transactionEntryHasInvalidVerb", nextEntry.getTransaction().getMethod()));
|
||||
}
|
||||
|
||||
String resourceType = res != null ? getContext().getResourceDefinition(res).getName() : null;
|
||||
|
||||
switch (verb) {
|
||||
case POST: {
|
||||
// CREATE
|
||||
|
@ -182,7 +188,7 @@ public class FhirSystemDaoDstu2 extends BaseFhirSystemDao<Bundle> {
|
|||
DaoMethodOutcome outcome;
|
||||
Entry newEntry = response.addEntry();
|
||||
outcome = resourceDao.create(res, nextEntry.getTransaction().getIfNoneExist(), false);
|
||||
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, newEntry);
|
||||
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, newEntry, resourceType);
|
||||
break;
|
||||
}
|
||||
case DELETE: {
|
||||
|
@ -218,7 +224,7 @@ public class FhirSystemDaoDstu2 extends BaseFhirSystemDao<Bundle> {
|
|||
outcome = resourceDao.update(res, parts.getResourceType() + '?' + parts.getParams(), false);
|
||||
}
|
||||
|
||||
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, newEntry);
|
||||
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, newEntry, resourceType);
|
||||
break;
|
||||
}
|
||||
case GET: {
|
||||
|
@ -249,7 +255,8 @@ public class FhirSystemDaoDstu2 extends BaseFhirSystemDao<Bundle> {
|
|||
|
||||
int configuredMax = 100; // this should probably be configurable or something
|
||||
if (bundle.size() > configuredMax) {
|
||||
oo.addIssue().setSeverity(IssueSeverityEnum.WARNING).setDetails("Search nested within transaction found more than " + configuredMax + " matches, but paging is not supported in nested transactions");
|
||||
oo.addIssue().setSeverity(IssueSeverityEnum.WARNING)
|
||||
.setDetails("Search nested within transaction found more than " + configuredMax + " matches, but paging is not supported in nested transactions");
|
||||
}
|
||||
List<IBaseResource> resourcesToAdd = bundle.getResources(0, Math.min(bundle.size(), configuredMax));
|
||||
for (IBaseResource next : resourcesToAdd) {
|
||||
|
@ -330,16 +337,18 @@ public class FhirSystemDaoDstu2 extends BaseFhirSystemDao<Bundle> {
|
|||
return url;
|
||||
}
|
||||
|
||||
private static void handleTransactionCreateOrUpdateOutcome(Map<IdDt, IdDt> idSubstitutions, Map<IdDt, DaoMethodOutcome> idToPersistedOutcome, IdDt nextResourceId, DaoMethodOutcome outcome, Entry newEntry) {
|
||||
private static void handleTransactionCreateOrUpdateOutcome(Map<IdDt, IdDt> idSubstitutions, Map<IdDt, DaoMethodOutcome> idToPersistedOutcome, IdDt nextResourceId, DaoMethodOutcome outcome,
|
||||
Entry newEntry, String theResourceType) {
|
||||
IdDt newId = outcome.getId().toUnqualifiedVersionless();
|
||||
IdDt resourceId = nextResourceId.toUnqualifiedVersionless();
|
||||
IdDt resourceId = nextResourceId.isLocal() ? nextResourceId : nextResourceId.toUnqualifiedVersionless();
|
||||
if (newId.equals(resourceId) == false) {
|
||||
/*
|
||||
* The correct way for substitution IDs to be is to be with no resource type, but we'll accept the qualified
|
||||
* kind too just to be lenient.
|
||||
*/
|
||||
idSubstitutions.put(resourceId, newId);
|
||||
idSubstitutions.put(resourceId.withResourceType(null), newId);
|
||||
if (resourceId.isLocal()) {
|
||||
/*
|
||||
* The correct way for substitution IDs to be is to be with no resource type, but we'll accept the qualified kind too just to be lenient.
|
||||
*/
|
||||
idSubstitutions.put(new IdDt(theResourceType + '/' + resourceId.getValue()), newId);
|
||||
}
|
||||
}
|
||||
idToPersistedOutcome.put(newId, outcome);
|
||||
if (outcome.getCreated().booleanValue()) {
|
||||
|
|
|
@ -50,17 +50,17 @@ public class ResourceLink implements Serializable {
|
|||
private String mySourcePath;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "SRC_RESOURCE_ID", referencedColumnName="RES_ID")
|
||||
@JoinColumn(name = "SRC_RESOURCE_ID", referencedColumnName="RES_ID", nullable=false)
|
||||
private ResourceTable mySourceResource;
|
||||
|
||||
@Column(name = "SRC_RESOURCE_ID", insertable = false, updatable = false)
|
||||
@Column(name = "SRC_RESOURCE_ID", insertable = false, updatable = false, nullable=false)
|
||||
private Long mySourceResourcePid;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "TARGET_RESOURCE_ID", referencedColumnName="RES_ID")
|
||||
@JoinColumn(name = "TARGET_RESOURCE_ID", referencedColumnName="RES_ID", nullable=false)
|
||||
private ResourceTable myTargetResource;
|
||||
|
||||
@Column(name = "TARGET_RESOURCE_ID", insertable = false, updatable = false)
|
||||
@Column(name = "TARGET_RESOURCE_ID", insertable = false, updatable = false,nullable=false)
|
||||
private Long myTargetResourcePid;
|
||||
|
||||
public ResourceLink() {
|
||||
|
|
|
@ -154,7 +154,7 @@ public class JpaResourceProviderDstu2<T extends IResource> extends BaseJpaResour
|
|||
}
|
||||
|
||||
@Validate
|
||||
public MethodOutcome validate(@ResourceParam T theResource, @ResourceParam String theRawResource, @ResourceParam EncodingEnum theEncoding, @Validate.Mode ValidationModeEnum theMode,
|
||||
public MethodOutcome validate(@ResourceParam T theResource, @IdParam IdDt theId, @ResourceParam String theRawResource, @ResourceParam EncodingEnum theEncoding, @Validate.Mode ValidationModeEnum theMode,
|
||||
@Validate.Profile String theProfile) {
|
||||
|
||||
final OperationOutcome oo = new OperationOutcome();
|
||||
|
|
|
@ -1395,6 +1395,12 @@ public class FhirResourceDaoDstu2Test {
|
|||
assertEquals(1, result.size());
|
||||
assertEquals(obsId01.getIdPart(), result.get(0).getId().getIdPart());
|
||||
|
||||
result = toList(ourObservationDao.search(Observation.SP_PATIENT, new ReferenceParam(patientId01.getIdPart())));
|
||||
assertEquals(1, result.size());
|
||||
|
||||
result = toList(ourObservationDao.search(Observation.SP_PATIENT, new ReferenceParam(patientId01.getIdPart())));
|
||||
assertEquals(1, result.size());
|
||||
|
||||
result = toList(ourObservationDao.search(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_IDENTIFIER, "999999999999")));
|
||||
assertEquals(0, result.size());
|
||||
|
||||
|
|
|
@ -358,7 +358,10 @@ public class FhirSystemDaoDstu1Test {
|
|||
|
||||
List<IResource> response = ourSystemDao.transaction(res);
|
||||
|
||||
ourLog.info(ourFhirContext.newXmlParser().setPrettyPrint(true).encodeResourceToString(response.get(0)));
|
||||
String encodeResourceToString = ourFhirContext.newXmlParser().setPrettyPrint(true).encodeResourceToString(response.get(0));
|
||||
ourLog.info(encodeResourceToString);
|
||||
|
||||
assertThat(encodeResourceToString, not(containsString("smsp")));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -846,7 +846,7 @@ public class FhirSystemDaoDstu2Test {
|
|||
assertEquals(OperationOutcome.class, resp.getEntry().get(0).getResource().getClass());
|
||||
|
||||
OperationOutcome outcome = (OperationOutcome) resp.getEntry().get(0).getResource();
|
||||
assertThat(outcome.getIssue().get(1).getDetails(), containsString("Placeholder resource ID \"Patient/urn:oid:0.1.2.3\" was replaced with permanent ID \"Patient/"));
|
||||
assertThat(outcome.getIssue().get(1).getDetails(), containsString("Placeholder resource ID \"urn:oid:0.1.2.3\" was replaced with permanent ID \"Patient/"));
|
||||
|
||||
assertTrue(resp.getEntry().get(1).getTransactionResponse().getLocation(), new IdDt(resp.getEntry().get(1).getTransactionResponse().getLocation()).getIdPart().matches("^[0-9]+$"));
|
||||
assertTrue(resp.getEntry().get(2).getTransactionResponse().getLocation(), new IdDt(resp.getEntry().get(2).getTransactionResponse().getLocation()).getIdPart().matches("^[0-9]+$"));
|
||||
|
@ -894,7 +894,7 @@ public class FhirSystemDaoDstu2Test {
|
|||
assertEquals(OperationOutcome.class, resp.getEntry().get(0).getResource().getClass());
|
||||
|
||||
OperationOutcome outcome = (OperationOutcome) resp.getEntry().get(0).getResource();
|
||||
assertThat(outcome.getIssue().get(1).getDetails(), containsString("Placeholder resource ID \"Patient/urn:oid:0.1.2.3\" was replaced with permanent ID \"Patient/"));
|
||||
assertThat(outcome.getIssue().get(1).getDetails(), containsString("Placeholder resource ID \"urn:oid:0.1.2.3\" was replaced with permanent ID \"Patient/"));
|
||||
|
||||
assertTrue(resp.getEntry().get(1).getTransactionResponse().getLocation(), new IdDt(resp.getEntry().get(1).getTransactionResponse().getLocation()).getIdPart().matches("^[0-9]+$"));
|
||||
assertTrue(resp.getEntry().get(2).getTransactionResponse().getLocation(), new IdDt(resp.getEntry().get(2).getTransactionResponse().getLocation()).getIdPart().matches("^[0-9]+$"));
|
||||
|
|
|
@ -82,6 +82,7 @@ import ca.uhn.fhir.rest.client.IGenericClient;
|
|||
import ca.uhn.fhir.rest.client.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.rest.gclient.IQuery;
|
||||
import ca.uhn.fhir.rest.gclient.IReadExecutable;
|
||||
import ca.uhn.fhir.rest.gclient.StringClientParam;
|
||||
import ca.uhn.fhir.rest.gclient.TokenClientParam;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
|
@ -410,6 +411,34 @@ public class ResourceProviderDstu2Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBundleCreate() throws Exception {
|
||||
IGenericClient client = ourClient;
|
||||
|
||||
String resBody = IOUtils.toString(ResourceProviderDstu2Test.class.getResource("/document-father.json"));
|
||||
IdDt id = client.create().resource(resBody).execute().getId();
|
||||
|
||||
ourLog.info("Created: {}", id);
|
||||
|
||||
ca.uhn.fhir.model.dstu2.resource.Bundle bundle = client.read().resource(ca.uhn.fhir.model.dstu2.resource.Bundle.class).withId(id).execute();
|
||||
|
||||
ourLog.info(ourFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBundleCreateWithTypeTransaction() throws Exception {
|
||||
IGenericClient client = ourClient;
|
||||
|
||||
String resBody = IOUtils.toString(ResourceProviderDstu2Test.class.getResource("/document-father.json"));
|
||||
resBody = resBody.replace("\"type\": \"document\"", "\"type\": \"transaction\"");
|
||||
try {
|
||||
client.create().resource(resBody).execute().getId();
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage(), containsString("Unable to store a Bundle resource on this server with a Bundle.type value other than 'document' - Value was: transaction"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See #147
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,475 @@
|
|||
{
|
||||
"resourceType": "Bundle",
|
||||
"meta": {
|
||||
"lastUpdated": "2013-05-28T22:12:21Z",
|
||||
"tag": [
|
||||
{
|
||||
"system": "http://hl7.org/fhir/tag",
|
||||
"code": "document"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "document",
|
||||
"base": "http://fhir.healthintersections.com.au/open",
|
||||
"entry": [
|
||||
{
|
||||
"base": "urn:uuid:",
|
||||
"resource": {
|
||||
"resourceType": "Composition",
|
||||
"id": "180f219f-97a8-486d-99d9-ed631fe4fc57",
|
||||
"meta": {
|
||||
"lastUpdated": "2013-05-28T22:12:21Z"
|
||||
},
|
||||
"text": {
|
||||
"status": "generated",
|
||||
"div": "<div><p><b>Generated Narrative with Details</b></p><p><b>id</b>: 180f219f-97a8-486d-99d9-ed631fe4fc57</p><p><b>meta</b>: </p><p><b>date</b>: Feb 1, 2013 12:30:02 PM</p><p><b>type</b>: Discharge Summary from Responsible Clinician <span>(Details : {LOINC code '28655-9' = 'Physician attending Discharge summary)</span></p><p><b>status</b>: final</p><p><b>confidentiality</b>: N</p><p><b>author</b>: <a>Doctor Dave. Generated Summary: 23; Adam Careful </a></p><p><b>encounter</b>: <a>http://fhir.healthintersections.com.au/open/Encounter/doc-example</a></p></div>"
|
||||
},
|
||||
"date": "2013-02-01T12:30:02Z",
|
||||
"type": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://loinc.org",
|
||||
"code": "28655-9"
|
||||
}
|
||||
],
|
||||
"text": "Discharge Summary from Responsible Clinician"
|
||||
},
|
||||
"status": "final",
|
||||
"confidentiality": "N",
|
||||
"subject": {
|
||||
"reference": "http://fhir.healthintersections.com.au/open/Patient/d1",
|
||||
"display": "Eve Everywoman"
|
||||
},
|
||||
"author": [
|
||||
{
|
||||
"reference": "Practitioner/example",
|
||||
"display": "Doctor Dave"
|
||||
}
|
||||
],
|
||||
"encounter": {
|
||||
"reference": "http://fhir.healthintersections.com.au/open/Encounter/doc-example"
|
||||
},
|
||||
"section": [
|
||||
{
|
||||
"title": "Reason for admission",
|
||||
"content": {
|
||||
"reference": "urn:uuid:d0dd51d3-3ab2-4c84-b697-a630c3e40e7a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Medications on Discharge",
|
||||
"content": {
|
||||
"reference": "urn:uuid:673f8db5-0ffd-4395-9657-6da00420bbc1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Known allergies",
|
||||
"content": {
|
||||
"reference": "urn:uuid:68f86194-e6e1-4f65-b64a-5314256f8d7b"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"resource": {
|
||||
"resourceType": "Practitioner",
|
||||
"id": "example",
|
||||
"meta": {
|
||||
"lastUpdated": "2013-05-05T16:13:03Z"
|
||||
},
|
||||
"text": {
|
||||
"status": "generated",
|
||||
"div": "<div>\n \n <p>Dr Adam Careful is a Referring Practitioner for Acme Hospital from 1-Jan 2012 to 31-Mar\n 2012</p>\n \n </div>"
|
||||
},
|
||||
"identifier": [
|
||||
{
|
||||
"system": "http://www.acme.org/practitioners",
|
||||
"value": "23"
|
||||
}
|
||||
],
|
||||
"name": {
|
||||
"family": [
|
||||
"Careful"
|
||||
],
|
||||
"given": [
|
||||
"Adam"
|
||||
],
|
||||
"prefix": [
|
||||
"Dr"
|
||||
]
|
||||
},
|
||||
"practitionerRole": [
|
||||
{
|
||||
"managingOrganization": {
|
||||
"reference": "Organization/1"
|
||||
},
|
||||
"role": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://hl7.org/fhir/v2/0286",
|
||||
"code": "RP"
|
||||
}
|
||||
]
|
||||
},
|
||||
"period": {
|
||||
"start": "2012-01-01",
|
||||
"end": "2012-03-31"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"resource": {
|
||||
"resourceType": "Patient",
|
||||
"id": "d1",
|
||||
"text": {
|
||||
"status": "generated",
|
||||
"div": "<div>\n <h1>Eve Everywoman</h1>\n </div>"
|
||||
},
|
||||
"name": [
|
||||
{
|
||||
"text": "Eve Everywoman",
|
||||
"family": [
|
||||
"Everywoman1"
|
||||
],
|
||||
"given": [
|
||||
"Eve"
|
||||
]
|
||||
}
|
||||
],
|
||||
"telecom": [
|
||||
{
|
||||
"system": "phone",
|
||||
"value": "555-555-2003",
|
||||
"use": "work"
|
||||
}
|
||||
],
|
||||
"gender": "female",
|
||||
"birthDate": "1955-01-06",
|
||||
"address": [
|
||||
{
|
||||
"use": "home",
|
||||
"line": [
|
||||
"2222 Home Street"
|
||||
]
|
||||
}
|
||||
],
|
||||
"active": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"resource": {
|
||||
"resourceType": "Encounter",
|
||||
"id": "doc-example",
|
||||
"meta": {
|
||||
"lastUpdated": "2013-05-05T16:13:03Z"
|
||||
},
|
||||
"text": {
|
||||
"status": "generated",
|
||||
"div": "<div> Admitted to Orthopedics Service,\n Middlemore Hospital between Jan 20 and Feb ist 2013 </div>"
|
||||
},
|
||||
"identifier": [
|
||||
{
|
||||
"value": "S100"
|
||||
}
|
||||
],
|
||||
"status": "finished",
|
||||
"class": "inpatient",
|
||||
"type": [
|
||||
{
|
||||
"text": "Orthopedic Admission"
|
||||
}
|
||||
],
|
||||
"patient": {
|
||||
"reference": "Patient/d1"
|
||||
},
|
||||
"period": {
|
||||
"start": "2013-01-20T12:30:02Z",
|
||||
"end": "2013-02-01T12:30:02Z"
|
||||
},
|
||||
"hospitalization": {
|
||||
"dischargeDisposition": {
|
||||
"text": "Discharged to care of GP"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"base": "urn:uuid:",
|
||||
"resource": {
|
||||
"resourceType": "List",
|
||||
"id": "d0dd51d3-3ab2-4c84-b697-a630c3e40e7a",
|
||||
"meta": {
|
||||
"lastUpdated": "2013-05-05T16:13:03Z"
|
||||
},
|
||||
"text": {
|
||||
"status": "additional",
|
||||
"div": "<div>\n <table>\n <thead>\n <tr>\n <td>Details</td>\n <td/>\n </tr>\n </thead>\n <tbody>\n <tr>\n <td>Acute Asthmatic attack. Was wheezing\n for days prior to admission.</td>\n <td/>\n </tr>\n </tbody>\n </table>\n </div>"
|
||||
},
|
||||
"code": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://loinc.org",
|
||||
"code": "8646-2",
|
||||
"display": "Hospital admission diagnosis"
|
||||
}
|
||||
]
|
||||
},
|
||||
"subject": {
|
||||
"reference": "http://fhir.healthintersections.com.au/open/Patient/d1",
|
||||
"display": "Peter Patient"
|
||||
},
|
||||
"status": "current",
|
||||
"mode": "working",
|
||||
"entry": [
|
||||
{
|
||||
"item": {
|
||||
"reference": "urn:uuid:541a72a8-df75-4484-ac89-ac4923f03b81"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"base": "urn:uuid:",
|
||||
"resource": {
|
||||
"resourceType": "Observation",
|
||||
"id": "541a72a8-df75-4484-ac89-ac4923f03b81",
|
||||
"meta": {
|
||||
"lastUpdated": "2013-05-05T16:13:03Z"
|
||||
},
|
||||
"text": {
|
||||
"status": "additional",
|
||||
"div": "<div> Acute Asthmatic attack. Was wheezing\n for days prior to admission. </div>"
|
||||
},
|
||||
"code": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://loinc.org",
|
||||
"code": "46241-6"
|
||||
}
|
||||
],
|
||||
"text": "Reason for admission"
|
||||
},
|
||||
"valueString": "Acute Asthmatic attack. Was wheezing for days prior to admission.",
|
||||
"status": "final",
|
||||
"reliability": "ok"
|
||||
}
|
||||
},
|
||||
{
|
||||
"base": "urn:uuid:",
|
||||
"resource": {
|
||||
"resourceType": "List",
|
||||
"id": "673f8db5-0ffd-4395-9657-6da00420bbc1",
|
||||
"meta": {
|
||||
"lastUpdated": "2013-05-05T16:13:03Z"
|
||||
},
|
||||
"text": {
|
||||
"status": "additional",
|
||||
"div": "<div>\n <table>\n <thead>\n <tr>\n <td>Medication</td>\n <td>Last Change</td>\n <td>Last ChangeReason</td>\n </tr>\n </thead>\n <tbody>\n <tr>\n <td>Theophylline 200mg BD after meals</td>\n <td>continued</td>\n </tr>\n <tr>\n <td>Ventolin Inhaler</td>\n <td>stopped</td>\n <td>Getting side effect of tremor</td>\n </tr>\n </tbody>\n </table>\n </div>"
|
||||
},
|
||||
"code": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://loinc.org",
|
||||
"code": "10183-2",
|
||||
"display": "Hospital discharge medications"
|
||||
}
|
||||
]
|
||||
},
|
||||
"subject": {
|
||||
"reference": "http://fhir.healthintersections.com.au/open/Patient/d1",
|
||||
"display": "Peter Patient"
|
||||
},
|
||||
"status": "current",
|
||||
"mode": "working",
|
||||
"entry": [
|
||||
{
|
||||
"flag": [
|
||||
{
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://www.ithealthboard.health.nz/fhir/ValueSet/medicationStatus",
|
||||
"code": "started"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"item": {
|
||||
"reference": "urn:uuid:124a6916-5d84-4b8c-b250-10cefb8e6e86"
|
||||
}
|
||||
},
|
||||
{
|
||||
"flag": [
|
||||
{
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://www.ithealthboard.health.nz/fhir/ValueSet/medicationStatus",
|
||||
"code": "stopped"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"deleted": true,
|
||||
"item": {
|
||||
"reference": "MedicationPrescription/1",
|
||||
"display": "use of Ventolin Inhaler was discontinued"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"base": "urn:uuid:",
|
||||
"resource": {
|
||||
"resourceType": "MedicationPrescription",
|
||||
"id": "124a6916-5d84-4b8c-b250-10cefb8e6e86",
|
||||
"meta": {
|
||||
"lastUpdated": "2013-05-05T16:13:03Z"
|
||||
},
|
||||
"text": {
|
||||
"status": "generated",
|
||||
"div": "<div>\n <p>Theophylline 200mg twice a day</p>\n </div>"
|
||||
},
|
||||
"contained": [
|
||||
{
|
||||
"resourceType": "Medication",
|
||||
"id": "med1",
|
||||
"name": "Theophylline 200mg",
|
||||
"code": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://snomed.info/sct",
|
||||
"code": "66493003"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"patient": {
|
||||
"reference": "http://fhir.healthintersections.com.au/open/Patient/d1",
|
||||
"display": "Peter Patient"
|
||||
},
|
||||
"prescriber": {
|
||||
"reference": "Practitioner/example",
|
||||
"display": "Peter Practitioner"
|
||||
},
|
||||
"reasonCodeableConcept": {
|
||||
"text": "Management of Asthma"
|
||||
},
|
||||
"medicationReference": {
|
||||
"reference": "#med1",
|
||||
"display": "Theophylline 200mg BD"
|
||||
},
|
||||
"dosageInstruction": [
|
||||
{
|
||||
"additionalInstructions": {
|
||||
"text": "Take with Food"
|
||||
},
|
||||
"scheduledTiming": {
|
||||
"repeat": {
|
||||
"frequency": 2,
|
||||
"period": 1,
|
||||
"periodUnits": "d"
|
||||
}
|
||||
},
|
||||
"route": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://snomed.info/sct",
|
||||
"code": "394899003",
|
||||
"display": "oral administration of treatment"
|
||||
}
|
||||
]
|
||||
},
|
||||
"doseQuantity": {
|
||||
"value": 1,
|
||||
"units": "tablet",
|
||||
"system": "http://unitsofmeasure.org",
|
||||
"code": "tbl"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"base": "urn:uuid:",
|
||||
"resource": {
|
||||
"resourceType": "List",
|
||||
"id": "68f86194-e6e1-4f65-b64a-5314256f8d7b",
|
||||
"meta": {
|
||||
"lastUpdated": "2013-05-05T16:13:03Z"
|
||||
},
|
||||
"text": {
|
||||
"status": "additional",
|
||||
"div": "<div>\n <table>\n <thead>\n <tr>\n <td>Allergen</td>\n <td>Reaction</td>\n </tr>\n </thead>\n <tbody>\n <tr>\n <td>Doxycycline</td>\n <td>Hives</td>\n </tr>\n </tbody>\n </table>\n </div>"
|
||||
},
|
||||
"code": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://loinc.org",
|
||||
"code": "48765-2",
|
||||
"display": "Allergies and adverse reactions Document"
|
||||
}
|
||||
]
|
||||
},
|
||||
"subject": {
|
||||
"reference": "http://fhir.healthintersections.com.au/open/Patient/d1",
|
||||
"display": "Peter Patient"
|
||||
},
|
||||
"status": "current",
|
||||
"mode": "working",
|
||||
"entry": [
|
||||
{
|
||||
"item": {
|
||||
"reference": "urn:uuid:47600e0f-b6b5-4308-84b5-5dec157f7637"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"base": "urn:uuid:",
|
||||
"resource": {
|
||||
"resourceType": "AllergyIntolerance",
|
||||
"id": "47600e0f-b6b5-4308-84b5-5dec157f7637",
|
||||
"meta": {
|
||||
"lastUpdated": "2013-05-05T16:13:03Z"
|
||||
},
|
||||
"text": {
|
||||
"status": "generated",
|
||||
"div": "<div>Sensitivity to Doxycycline :\n Hives</div>"
|
||||
},
|
||||
"recordedDate": "2012-09-17",
|
||||
"patient": {
|
||||
"reference": "http://fhir.healthintersections.com.au/open/Patient/d1",
|
||||
"display": "Eve Everywoman"
|
||||
},
|
||||
"substance": {
|
||||
"text": "Doxycycline"
|
||||
},
|
||||
"status": "confirmed",
|
||||
"criticality": "high",
|
||||
"type": "immune",
|
||||
"event": [
|
||||
{
|
||||
"manifestation": [
|
||||
{
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://example.org/system",
|
||||
"code": "xxx",
|
||||
"display": "Hives"
|
||||
}
|
||||
],
|
||||
"text": "Hives"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -34,6 +34,22 @@ public class IdDtTest {
|
|||
assertFalse(id.isLocal());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetectLocalBase() {
|
||||
assertEquals("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57", new IdDt("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57").getValue());
|
||||
assertEquals("urn:uuid:", new IdDt("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57").getBaseUrl());
|
||||
assertEquals("180f219f-97a8-486d-99d9-ed631fe4fc57", new IdDt("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57").getIdPart());
|
||||
|
||||
assertEquals("cid:180f219f-97a8-486d-99d9-ed631fe4fc57", new IdDt("cid:180f219f-97a8-486d-99d9-ed631fe4fc57").getValue());
|
||||
assertEquals("cid:", new IdDt("cid:180f219f-97a8-486d-99d9-ed631fe4fc57").getBaseUrl());
|
||||
assertEquals("180f219f-97a8-486d-99d9-ed631fe4fc57", new IdDt("cid:180f219f-97a8-486d-99d9-ed631fe4fc57").getIdPart());
|
||||
|
||||
assertEquals("#180f219f-97a8-486d-99d9-ed631fe4fc57", new IdDt("#180f219f-97a8-486d-99d9-ed631fe4fc57").getValue());
|
||||
assertEquals("#", new IdDt("#180f219f-97a8-486d-99d9-ed631fe4fc57").getBaseUrl());
|
||||
assertEquals("180f219f-97a8-486d-99d9-ed631fe4fc57", new IdDt("#180f219f-97a8-486d-99d9-ed631fe4fc57").getIdPart());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See #67
|
||||
*/
|
||||
|
@ -41,34 +57,11 @@ public class IdDtTest {
|
|||
public void testComplicatedLocal() {
|
||||
IdDt id = new IdDt("#Patient/cid:Patient-72/_history/1");
|
||||
assertTrue(id.isLocal());
|
||||
assertNull(id.getBaseUrl());
|
||||
assertEquals("#", id.getBaseUrl());
|
||||
assertNull(id.getResourceType());
|
||||
assertNull(id.getVersionIdPart());
|
||||
assertEquals("#Patient/cid:Patient-72/_history/1", id.getIdPart());
|
||||
assertEquals("Patient/cid:Patient-72/_history/1", id.getIdPart());
|
||||
|
||||
IdDt id2 = new IdDt("#Patient/cid:Patient-72/_history/1");
|
||||
assertEquals(id, id2);
|
||||
|
||||
id2 = id2.toUnqualified();
|
||||
assertTrue(id2.isLocal());
|
||||
assertNull(id2.getBaseUrl());
|
||||
assertNull(id2.getResourceType());
|
||||
assertNull(id2.getVersionIdPart());
|
||||
assertEquals("#Patient/cid:Patient-72/_history/1", id2.getIdPart());
|
||||
|
||||
id2 = id2.toVersionless();
|
||||
assertTrue(id2.isLocal());
|
||||
assertNull(id2.getBaseUrl());
|
||||
assertNull(id2.getResourceType());
|
||||
assertNull(id2.getVersionIdPart());
|
||||
assertEquals("#Patient/cid:Patient-72/_history/1", id2.getIdPart());
|
||||
|
||||
id2 = id2.toUnqualifiedVersionless();
|
||||
assertTrue(id2.isLocal());
|
||||
assertNull(id2.getBaseUrl());
|
||||
assertNull(id2.getResourceType());
|
||||
assertNull(id2.getVersionIdPart());
|
||||
assertEquals("#Patient/cid:Patient-72/_history/1", id2.getIdPart());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -99,7 +99,7 @@ public class JsonParserTest {
|
|||
|
||||
assertEquals(exp, act);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDecimalPrecisionPreserved() {
|
||||
String number = "52.3779939997090374535378485873776474764643249869328698436986235758587";
|
||||
|
|
|
@ -537,6 +537,8 @@ public class XmlParserTest {
|
|||
// Re-parse the bundle
|
||||
patient = (Patient) xmlParser.parseResource(xmlParser.encodeResourceToString(patient));
|
||||
assertEquals("#1", patient.getManagingOrganization().getReference().getValue());
|
||||
assertEquals("#", patient.getManagingOrganization().getReference().getBaseUrl());
|
||||
assertEquals("1", patient.getManagingOrganization().getReference().getIdPart());
|
||||
|
||||
assertNotNull(patient.getManagingOrganization().getResource());
|
||||
org = (Organization) patient.getManagingOrganization().getResource();
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
package ca.uhn.fhir.parser;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
@ -14,7 +20,6 @@ import net.sf.json.JsonConfig;
|
|||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.hamcrest.core.StringContains;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -64,6 +69,87 @@ public class JsonParserDstu2Test {
|
|||
assertThat(ourCtx.newJsonParser().setOmitResourceId(true).encodeResourceToString(p), not(containsString("123")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseAndEncodeBundleWithUuidBase() {
|
||||
//@formatter:off
|
||||
String input =
|
||||
"{\n" +
|
||||
" \"resourceType\":\"Bundle\",\n" +
|
||||
" \"type\":\"document\",\n" +
|
||||
" \"entry\":[\n" +
|
||||
" {\n" +
|
||||
" \"base\":\"urn:uuid:\",\n" +
|
||||
" \"resource\":{\n" +
|
||||
" \"resourceType\":\"Composition\",\n" +
|
||||
" \"id\":\"180f219f-97a8-486d-99d9-ed631fe4fc57\",\n" +
|
||||
" \"meta\":{\n" +
|
||||
" \"lastUpdated\":\"2013-05-28T22:12:21Z\"\n" +
|
||||
" },\n" +
|
||||
" \"text\":{\n" +
|
||||
" \"status\":\"generated\",\n" +
|
||||
" \"div\":\"<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\"><p><b>Generated Narrative with Details</b></p><p><b>id</b>: 180f219f-97a8-486d-99d9-ed631fe4fc57</p><p><b>meta</b>: </p><p><b>date</b>: Feb 1, 2013 12:30:02 PM</p><p><b>type</b>: Discharge Summary from Responsible Clinician <span>(Details : {LOINC code '28655-9' = 'Physician attending Discharge summary)</span></p><p><b>status</b>: final</p><p><b>confidentiality</b>: N</p><p><b>author</b>: <a>Doctor Dave. Generated Summary: 23; Adam Careful </a></p><p><b>encounter</b>: <a>http://fhir.healthintersections.com.au/open/Encounter/doc-example</a></p></div>\"\n" +
|
||||
" },\n" +
|
||||
" \"date\":\"2013-02-01T12:30:02Z\",\n" +
|
||||
" \"type\":{\n" +
|
||||
" \"coding\":[\n" +
|
||||
" {\n" +
|
||||
" \"system\":\"http://loinc.org\",\n" +
|
||||
" \"code\":\"28655-9\"\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"text\":\"Discharge Summary from Responsible Clinician\"\n" +
|
||||
" },\n" +
|
||||
" \"status\":\"final\",\n" +
|
||||
" \"confidentiality\":\"N\",\n" +
|
||||
" \"subject\":{\n" +
|
||||
" \"reference\":\"http://fhir.healthintersections.com.au/open/Patient/d1\",\n" +
|
||||
" \"display\":\"Eve Everywoman\"\n" +
|
||||
" },\n" +
|
||||
" \"author\":[\n" +
|
||||
" {\n" +
|
||||
" \"reference\":\"Practitioner/example\",\n" +
|
||||
" \"display\":\"Doctor Dave\"\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"encounter\":{\n" +
|
||||
" \"reference\":\"http://fhir.healthintersections.com.au/open/Encounter/doc-example\"\n" +
|
||||
" },\n" +
|
||||
" \"section\":[\n" +
|
||||
" {\n" +
|
||||
" \"title\":\"Reason for admission\",\n" +
|
||||
" \"content\":{\n" +
|
||||
" \"reference\":\"urn:uuid:d0dd51d3-3ab2-4c84-b697-a630c3e40e7a\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"title\":\"Medications on Discharge\",\n" +
|
||||
" \"content\":{\n" +
|
||||
" \"reference\":\"urn:uuid:673f8db5-0ffd-4395-9657-6da00420bbc1\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"title\":\"Known allergies\",\n" +
|
||||
" \"content\":{\n" +
|
||||
" \"reference\":\"urn:uuid:68f86194-e6e1-4f65-b64a-5314256f8d7b\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" }\n" +
|
||||
" }" +
|
||||
" ]" +
|
||||
"}";
|
||||
//@formatter:on
|
||||
|
||||
ca.uhn.fhir.model.dstu2.resource.Bundle parsed = ourCtx.newJsonParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, input);
|
||||
|
||||
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed);
|
||||
ourLog.info(encoded);
|
||||
|
||||
assertEquals("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57", parsed.getEntry().get(0).getResource().getId().getValue());
|
||||
assertEquals("urn:uuid:", parsed.getEntry().get(0).getResource().getId().getBaseUrl());
|
||||
assertEquals("180f219f-97a8-486d-99d9-ed631fe4fc57", parsed.getEntry().get(0).getResource().getId().getIdPart());
|
||||
assertThat(encoded, containsString("\"id\":\"180f219f-97a8-486d-99d9-ed631fe4fc57\""));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
|
|
|
@ -1108,7 +1108,15 @@ public class GenericClientDstu2Test {
|
|||
assertNotNull(response.getOperationOutcome());
|
||||
assertEquals("FOOBAR", response.getOperationOutcome().getIssueFirstRep().getDetailsElement().getValue());
|
||||
idx++;
|
||||
}
|
||||
|
||||
response = client.validate().resource(ourCtx.newJsonParser().encodeResourceToString(p)).prettyPrint().execute();
|
||||
assertEquals("http://example.com/fhir/Patient/$validate?_format=json&_pretty=true", capt.getAllValues().get(idx).getURI().toASCIIString());
|
||||
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
|
||||
assertThat(extractBody(capt, idx), containsString("\"resourceType\":\"Parameters\",\n"));
|
||||
assertNotNull(response.getOperationOutcome());
|
||||
assertEquals("FOOBAR", response.getOperationOutcome().getIssueFirstRep().getDetailsElement().getValue());
|
||||
idx++;
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
|
|
|
@ -29,7 +29,8 @@ package org.hl7.fhir.instance.model;
|
|||
|
||||
*/
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
|
@ -42,6 +43,8 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
|||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
|
||||
/**
|
||||
* This class represents the logical identity for a resource, or as much of that
|
||||
* identity is known. In FHIR, every resource must have a "logical ID" which
|
||||
|
@ -311,6 +314,11 @@ public final class IdType extends UriType implements IPrimitiveType<String>, IId
|
|||
public String getValue() {
|
||||
String retVal = super.getValue();
|
||||
if (retVal == null && myHaveComponentParts) {
|
||||
|
||||
if (determineLocalPrefix(myBaseUrl) != null && myResourceType == null && myUnqualifiedVersionId == null) {
|
||||
return myBaseUrl + myUnqualifiedId;
|
||||
}
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
if (isNotBlank(myBaseUrl)) {
|
||||
b.append(myBaseUrl);
|
||||
|
@ -428,9 +436,37 @@ public final class IdType extends UriType implements IPrimitiveType<String>, IId
|
|||
*/
|
||||
@Override
|
||||
public boolean isLocal() {
|
||||
return myUnqualifiedId != null && myUnqualifiedId.isEmpty() == false && myUnqualifiedId.charAt(0) == '#';
|
||||
return "#".equals(myBaseUrl);
|
||||
}
|
||||
|
||||
private String determineLocalPrefix(String theValue) {
|
||||
if (theValue == null || theValue.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (theValue.startsWith("#")) {
|
||||
return "#";
|
||||
}
|
||||
int lastPrefix = -1;
|
||||
for (int i = 0; i < theValue.length(); i++) {
|
||||
char nextChar = theValue.charAt(i);
|
||||
if (nextChar == ':') {
|
||||
lastPrefix = i;
|
||||
} else if (!Character.isLetter(nextChar) || !Character.isLowerCase(nextChar)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lastPrefix != -1) {
|
||||
String candidate = theValue.substring(0, lastPrefix + 1);
|
||||
if (candidate.startsWith("cid:") || candidate.startsWith("urn:")) {
|
||||
return candidate;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value
|
||||
*
|
||||
|
@ -443,22 +479,29 @@ public final class IdType extends UriType implements IPrimitiveType<String>, IId
|
|||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public IdType setValue(String theValue) {
|
||||
public IdType setValue(String theValue) throws DataFormatException {
|
||||
// TODO: add validation
|
||||
super.setValue(theValue);
|
||||
myHaveComponentParts = false;
|
||||
|
||||
String localPrefix = determineLocalPrefix(theValue);
|
||||
|
||||
if (StringUtils.isBlank(theValue)) {
|
||||
myBaseUrl = null;
|
||||
super.setValue(null);
|
||||
myUnqualifiedId = null;
|
||||
myUnqualifiedVersionId = null;
|
||||
myResourceType = null;
|
||||
} else if (theValue.charAt(0) == '#') {
|
||||
} else if (theValue.charAt(0) == '#' && theValue.length() > 1) {
|
||||
super.setValue(theValue);
|
||||
myUnqualifiedId = theValue;
|
||||
myBaseUrl = "#";
|
||||
myUnqualifiedId = theValue.substring(1);
|
||||
myUnqualifiedVersionId = null;
|
||||
myResourceType = null;
|
||||
myHaveComponentParts = true;
|
||||
} else if (localPrefix != null) {
|
||||
myBaseUrl = localPrefix;
|
||||
myUnqualifiedId = theValue.substring(localPrefix.length());
|
||||
} else {
|
||||
int vidIndex = theValue.indexOf("/_history/");
|
||||
int idIndex;
|
||||
|
|
|
@ -0,0 +1,226 @@
|
|||
package ca.uhn.fhir.model;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.hl7.fhir.instance.model.IdType;
|
||||
import org.hl7.fhir.instance.model.Patient;
|
||||
import org.hl7.fhir.instance.model.Reference;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
|
||||
public class IdTypeTest {
|
||||
|
||||
private static FhirContext ourCtx;
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(IdTypeTest.class);
|
||||
|
||||
@Test
|
||||
public void testDetectLocal() {
|
||||
IdType id;
|
||||
|
||||
id = new IdType("#123");
|
||||
assertEquals("#123", id.getValue());
|
||||
assertTrue(id.isLocal());
|
||||
|
||||
id = new IdType("#Medication/499059CE-CDD4-48BC-9014-528A35D15CED/_history/1");
|
||||
assertEquals("#Medication/499059CE-CDD4-48BC-9014-528A35D15CED/_history/1", id.getValue());
|
||||
assertTrue(id.isLocal());
|
||||
|
||||
id = new IdType("http://example.com/Patient/33#123");
|
||||
assertEquals("http://example.com/Patient/33#123", id.getValue());
|
||||
assertFalse(id.isLocal());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetectLocalBase() {
|
||||
assertEquals("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57").getValue());
|
||||
assertEquals("urn:uuid:", new IdType("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57").getBaseUrl());
|
||||
assertEquals("180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("urn:uuid:180f219f-97a8-486d-99d9-ed631fe4fc57").getIdPart());
|
||||
|
||||
assertEquals("cid:180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("cid:180f219f-97a8-486d-99d9-ed631fe4fc57").getValue());
|
||||
assertEquals("cid:", new IdType("cid:180f219f-97a8-486d-99d9-ed631fe4fc57").getBaseUrl());
|
||||
assertEquals("180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("cid:180f219f-97a8-486d-99d9-ed631fe4fc57").getIdPart());
|
||||
|
||||
assertEquals("#180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("#180f219f-97a8-486d-99d9-ed631fe4fc57").getValue());
|
||||
assertEquals("#", new IdType("#180f219f-97a8-486d-99d9-ed631fe4fc57").getBaseUrl());
|
||||
assertEquals("180f219f-97a8-486d-99d9-ed631fe4fc57", new IdType("#180f219f-97a8-486d-99d9-ed631fe4fc57").getIdPart());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See #67
|
||||
*/
|
||||
@Test
|
||||
public void testComplicatedLocal() {
|
||||
IdType id = new IdType("#Patient/cid:Patient-72/_history/1");
|
||||
assertTrue(id.isLocal());
|
||||
assertEquals("#", id.getBaseUrl());
|
||||
assertNull(id.getResourceType());
|
||||
assertNull(id.getVersionIdPart());
|
||||
assertEquals("Patient/cid:Patient-72/_history/1", id.getIdPart());
|
||||
|
||||
IdType id2 = new IdType("#Patient/cid:Patient-72/_history/1");
|
||||
assertEquals(id, id2);
|
||||
|
||||
id2 = id2.toUnqualified();
|
||||
assertFalse(id2.isLocal());
|
||||
assertNull(id2.getBaseUrl());
|
||||
assertNull(id2.getResourceType());
|
||||
assertNull(id2.getVersionIdPart());
|
||||
assertEquals("Patient/cid:Patient-72/_history/1", id2.getIdPart());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetermineBase() {
|
||||
|
||||
IdType rr;
|
||||
|
||||
rr = new IdType("http://foo/fhir/Organization/123");
|
||||
assertEquals("http://foo/fhir", rr.getBaseUrl());
|
||||
|
||||
rr = new IdType("http://foo/fhir/Organization/123/_history/123");
|
||||
assertEquals("http://foo/fhir", rr.getBaseUrl());
|
||||
|
||||
rr = new IdType("Organization/123/_history/123");
|
||||
assertEquals(null, rr.getBaseUrl());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseValueAbsolute() {
|
||||
Patient patient = new Patient();
|
||||
IdType rr = new IdType();
|
||||
rr.setValue("http://foo/fhir/Organization/123");
|
||||
|
||||
patient.setManagingOrganization(new Reference(rr));
|
||||
|
||||
Patient actual = parseAndEncode(patient);
|
||||
Reference ref = actual.getManagingOrganization();
|
||||
assertEquals("Organization", ref.getReferenceElement().getResourceType());
|
||||
assertEquals("123", ref.getReferenceElement().getIdPart());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBigDecimalIds() {
|
||||
|
||||
IdType id = new IdType(new BigDecimal("123"));
|
||||
assertEquals(id.getIdPartAsBigDecimal(), new BigDecimal("123"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseValueAbsoluteWithVersion() {
|
||||
Patient patient = new Patient();
|
||||
IdType rr = new IdType();
|
||||
rr.setValue("http://foo/fhir/Organization/123/_history/999");
|
||||
patient.setManagingOrganization(new Reference(rr));
|
||||
|
||||
Patient actual = parseAndEncode(patient);
|
||||
Reference ref = actual.getManagingOrganization();
|
||||
assertEquals("Organization", ref.getReferenceElement().getResourceType());
|
||||
assertEquals("123", ref.getReferenceElement().getIdPart());
|
||||
assertEquals(null, ref.getReferenceElement().getVersionIdPart());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testViewMethods() {
|
||||
IdType i = new IdType("http://foo/fhir/Organization/123/_history/999");
|
||||
assertEquals("Organization/123/_history/999", i.toUnqualified().getValue());
|
||||
assertEquals("http://foo/fhir/Organization/123", i.toVersionless().getValue());
|
||||
assertEquals("Organization/123", i.toUnqualifiedVersionless().getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseValueWithVersion() {
|
||||
Patient patient = new Patient();
|
||||
IdType rr = new IdType();
|
||||
rr.setValue("/123/_history/999");
|
||||
patient.setManagingOrganization(new Reference(rr));
|
||||
|
||||
Patient actual = parseAndEncode(patient);
|
||||
Reference ref = actual.getManagingOrganization();
|
||||
assertEquals(null, ref.getReferenceElement().getResourceType());
|
||||
assertEquals("123", ref.getReferenceElement().getIdPart());
|
||||
assertEquals(null, ref.getReferenceElement().getVersionIdPart());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseValueMissingType1() {
|
||||
Patient patient = new Patient();
|
||||
IdType rr = new IdType();
|
||||
rr.setValue("/123");
|
||||
patient.setManagingOrganization(new Reference(rr));
|
||||
|
||||
Patient actual = parseAndEncode(patient);
|
||||
Reference ref = actual.getManagingOrganization();
|
||||
assertEquals(null, ref.getReferenceElement().getResourceType());
|
||||
assertEquals("123", ref.getReferenceElement().getIdPart());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseValueMissingType2() {
|
||||
Patient patient = new Patient();
|
||||
IdType rr = new IdType();
|
||||
rr.setValue("123");
|
||||
patient.setManagingOrganization(new Reference(rr));
|
||||
|
||||
Patient actual = parseAndEncode(patient);
|
||||
Reference ref = actual.getManagingOrganization();
|
||||
assertEquals(null, ref.getReferenceElement().getResourceType());
|
||||
assertEquals("123", ref.getReferenceElement().getIdPart());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseValueRelative1() {
|
||||
Patient patient = new Patient();
|
||||
IdType rr = new IdType();
|
||||
rr.setValue("Organization/123");
|
||||
patient.setManagingOrganization(new Reference(rr));
|
||||
|
||||
Patient actual = parseAndEncode(patient);
|
||||
Reference ref = actual.getManagingOrganization();
|
||||
assertEquals("Organization", ref.getReferenceElement().getResourceType());
|
||||
assertEquals("123", ref.getReferenceElement().getIdPart());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseValueRelative2() {
|
||||
Patient patient = new Patient();
|
||||
IdType rr = new IdType();
|
||||
rr.setValue("/Organization/123");
|
||||
patient.setManagingOrganization(new Reference(rr));
|
||||
|
||||
Patient actual = parseAndEncode(patient);
|
||||
Reference ref = actual.getManagingOrganization();
|
||||
assertEquals("Organization", ref.getReferenceElement().getResourceType());
|
||||
assertEquals("123", ref.getReferenceElement().getIdPart());
|
||||
|
||||
}
|
||||
|
||||
private Patient parseAndEncode(Patient patient) {
|
||||
String encoded = ourCtx.newXmlParser().encodeResourceToString(patient);
|
||||
ourLog.info("\n" + encoded);
|
||||
return ourCtx.newXmlParser().parseResource(Patient.class, encoded);
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
ourCtx = new FhirContext();
|
||||
}
|
||||
|
||||
}
|
|
@ -597,6 +597,7 @@ public class Controller {
|
|||
|
||||
CaptureInterceptor interceptor = new CaptureInterceptor();
|
||||
GenericClient client = theRequest.newClient(theReq, getContext(theRequest), myConfig, interceptor);
|
||||
client.setPrettyPrint(true);
|
||||
|
||||
Class<? extends IResource> type = null; // def.getImplementingClass();
|
||||
if ("history-type".equals(theMethod)) {
|
||||
|
@ -616,8 +617,10 @@ public class Controller {
|
|||
try {
|
||||
if (body.startsWith("{")) {
|
||||
resource = getContext(theRequest).newJsonParser().parseResource(type, body);
|
||||
client.setEncoding(EncodingEnum.JSON);
|
||||
} else if (body.startsWith("<")) {
|
||||
resource = getContext(theRequest).newXmlParser().parseResource(type, body);
|
||||
client.setEncoding(EncodingEnum.XML);
|
||||
} else {
|
||||
theModel.put("errorMsg", "Message body does not appear to be a valid FHIR resource instance document. Body should start with '<' (for XML encoding) or '{' (for JSON encoding).");
|
||||
return;
|
||||
|
@ -637,7 +640,7 @@ public class Controller {
|
|||
try {
|
||||
if (validate) {
|
||||
outcomeDescription = "Validate Resource";
|
||||
client.validate(resource);
|
||||
client.validate().resource(resource).prettyPrint().execute();
|
||||
} else {
|
||||
String id = theReq.getParameter("resource-create-id");
|
||||
if ("update".equals(theMethod)) {
|
||||
|
|
|
@ -92,9 +92,6 @@ public class TinderJpaRestServerMojo extends AbstractMojo {
|
|||
}
|
||||
for (String next : keys) {
|
||||
if (next.startsWith("resource.")) {
|
||||
if (next.endsWith(".Bundle")) {
|
||||
continue;
|
||||
}
|
||||
baseResourceNames.add(next.substring("resource.".length()).toLowerCase());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,8 @@ import org.apache.commons.lang3.StringUtils;
|
|||
|
||||
import ca.uhn.fhir.jpa.provider.JpaResourceProvider${versionCapitalized};
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.model.api.*;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.api.annotation.*;
|
||||
import ca.uhn.fhir.model.${version}.composite.*;
|
||||
import ca.uhn.fhir.model.${version}.resource.*;
|
||||
|
@ -16,7 +17,7 @@ import ca.uhn.fhir.rest.param.*;
|
|||
import ca.uhn.fhir.rest.api.SortSpec;
|
||||
import ca.uhn.fhir.model.dstu.resource.Binary;
|
||||
// import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
// import ca.uhn.fhir.model.api.Bundle;
|
||||
|
||||
public class ${className}ResourceProvider extends JpaResourceProvider${versionCapitalized}<${className}> {
|
||||
|
||||
|
|
|
@ -27,7 +27,12 @@
|
|||
</util:list>
|
||||
|
||||
#foreach ( $res in $resources )
|
||||
<bean id="my${res.name}Dao${versionCapitalized}" class="ca.uhn.fhir.jpa.dao.FhirResourceDao${versionCapitalized}">
|
||||
<bean id="my${res.name}Dao${versionCapitalized}"
|
||||
#if ( ${res.name} == 'Bundle' )
|
||||
class="ca.uhn.fhir.jpa.dao.Fhir${res.name}ResourceDao${versionCapitalized}">
|
||||
#else
|
||||
class="ca.uhn.fhir.jpa.dao.FhirResourceDao${versionCapitalized}">
|
||||
#end
|
||||
<property name="resourceType" value="ca.uhn.fhir.model.${version}.resource.${res.declaringClassNameComplete}"/>
|
||||
<property name="context" ref="myFhirContext${versionCapitalized}"/>
|
||||
</bean>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
<groupId>ca.uhn.hapi.example</groupId>
|
||||
<artifactId>restful-server-example</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<name>HAPI FHIR Sample RESTful Server</name>
|
||||
|
|
Loading…
Reference in New Issue