Squashed commit of the following:
commit df641506885e09e63f80efc6c658d01a1a3a8142 Author: James Agnew <jamesagnew@gmail.com> Date: Sat Sep 29 13:47:22 2018 -0400 Shrink validation resources commit 4c1550eafa26f4235b4b8804741aecc03276b5c6 Author: James Agnew <jamesagnew@gmail.com> Date: Fri Sep 28 22:45:28 2018 -0400 Updates to get R4 working commit 8332f15291006691ed9b07ead3e3524b0fc85510 Author: jamesagnew <jamesagnew@gmail.com> Date: Fri Sep 28 09:02:13 2018 -0400 Ongoing work on gettign R4 working commit f7146cab7aed937bb625a8aec95744d76db00041 Author: James Agnew <jamesagnew@gmail.com> Date: Fri Sep 28 05:21:01 2018 -0400 More work on sync commit f48de4a10b1bab2584fee813017d9b27b237bfa9 Merge: 9e4f3cc722 aacb78b779 Author: James Agnew <jamesagnew@gmail.com> Date: Thu Sep 27 20:11:29 2018 -0400 Merge branch 'sync_r4' of github.com:jamesagnew/hapi-fhir into sync_r4 commit 9e4f3cc722668aae31a77b19bf9b032af3ae01b0 Author: James Agnew <jamesagnew@gmail.com> Date: Thu Sep 27 20:11:19 2018 -0400 Fix compile error commit 7ec29e0ceda8f9013cbabb95767cbe15b4b81303 Merge: 23f7517325002c4b3ff7
Author: James Agnew <jamesagnew@gmail.com> Date: Thu Sep 27 20:04:23 2018 -0400 Merge branch 'master' into sync_r4 commit aacb78b7793ab2c71e0a2a774240ee2b5d3f9e7f Author: jamesagnew <jamesagnew@gmail.com> Date: Thu Sep 27 20:01:42 2018 -0400 Keep working on getting R4 building commit 4950de46d99897e74d41dfdb10d3d8a3435cb0c9 Author: jamesagnew <jamesagnew@gmail.com> Date: Tue Sep 25 13:11:27 2018 -0400 Ongoing work to get R4 working commit 819d69c20e112dd3c72569ec50114ddb8263c300 Author: jamesagnew <jamesagnew@gmail.com> Date: Thu Sep 20 08:15:36 2018 -0400 Work on getting build working commit 2c61b6cd1205ced5d7b822cf10942c69272ea078 Merge: 16b5bb06c8dfb4de86f1
Author: jamesagnew <jamesagnew@gmail.com> Date: Thu Sep 20 05:16:53 2018 -0400 Merge branch 'master' into sync_r4 commit 16b5bb06c8cdaf8d67c3b80f5aa9be9fccd99aef Author: jamesagnew <jamesagnew@gmail.com> Date: Mon Sep 17 05:30:39 2018 -0400 Work on R4 sync commit 23f7517325a14dd2ca1eb5641296ead2776634ae Author: James Agnew <jamesagnew@gmail.com> Date: Sun Sep 16 10:19:00 2018 -0400 Work on sync commit 6cc413c1f1dea538295aa4c16c21a5677494ac4c Author: James Agnew <jamesagnew@gmail.com> Date: Fri Sep 14 17:28:28 2018 -0400 Work on R$ sync commit df6f6ad2ce783b07ccc383134705d874bc5d2cf1 Author: jamesagnew <jamesagnew@gmail.com> Date: Fri Sep 14 08:33:07 2018 -0400 Work on R4
This commit is contained in:
parent
002c4b3ff7
commit
3e445faf47
|
@ -133,7 +133,7 @@ public class ParserOptions {
|
||||||
} else if (thePaths instanceof HashSet) {
|
} else if (thePaths instanceof HashSet) {
|
||||||
myDontStripVersionsFromReferencesAtPaths = (Set<String>) ((HashSet<String>) thePaths).clone();
|
myDontStripVersionsFromReferencesAtPaths = (Set<String>) ((HashSet<String>) thePaths).clone();
|
||||||
} else {
|
} else {
|
||||||
myDontStripVersionsFromReferencesAtPaths = new HashSet<String>(thePaths);
|
myDontStripVersionsFromReferencesAtPaths = new HashSet<>(thePaths);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,8 +201,10 @@ public class RuntimeResourceDefinition extends BaseRuntimeElementCompositeDefini
|
||||||
* SPs with the same path the same way. This behaviour is
|
* SPs with the same path the same way. This behaviour is
|
||||||
* used by AuthorizationInterceptor
|
* used by AuthorizationInterceptor
|
||||||
*/
|
*/
|
||||||
|
String nextPath = massagePathForCompartmentSimilarity(next.getPath());
|
||||||
for (RuntimeSearchParam nextAlternate : searchParams) {
|
for (RuntimeSearchParam nextAlternate : searchParams) {
|
||||||
if (nextAlternate.getPath().equals(next.getPath())) {
|
String nextAlternatePath = massagePathForCompartmentSimilarity(nextAlternate.getPath());
|
||||||
|
if (nextAlternatePath.equals(nextPath)) {
|
||||||
if (!nextAlternate.getName().equals(next.getName())) {
|
if (!nextAlternate.getName().equals(next.getName())) {
|
||||||
searchParamsForCompartment.add(nextAlternate);
|
searchParamsForCompartment.add(nextAlternate);
|
||||||
}
|
}
|
||||||
|
@ -236,6 +238,14 @@ public class RuntimeResourceDefinition extends BaseRuntimeElementCompositeDefini
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String massagePathForCompartmentSimilarity(String thePath) {
|
||||||
|
String path = thePath;
|
||||||
|
if (path.matches(".*\\.where\\(resolve\\(\\) is [a-zA-Z]+\\)")) {
|
||||||
|
path = path.substring(0, path.indexOf(".where"));
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public synchronized IBaseResource toProfile() {
|
public synchronized IBaseResource toProfile() {
|
||||||
validateSealed();
|
validateSealed();
|
||||||
|
|
|
@ -469,7 +469,7 @@ public abstract class BaseParser implements IParser {
|
||||||
TagList tags = ResourceMetadataKeyEnum.TAG_LIST.get(theIResource);
|
TagList tags = ResourceMetadataKeyEnum.TAG_LIST.get(theIResource);
|
||||||
if (shouldAddSubsettedTag()) {
|
if (shouldAddSubsettedTag()) {
|
||||||
tags = new TagList(tags);
|
tags = new TagList(tags);
|
||||||
tags.add(new Tag(Constants.TAG_SUBSETTED_SYSTEM, Constants.TAG_SUBSETTED_CODE, subsetDescription()));
|
tags.add(new Tag(getSubsettedCodeSystem(), Constants.TAG_SUBSETTED_CODE, subsetDescription()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return tags;
|
return tags;
|
||||||
|
@ -746,7 +746,7 @@ public abstract class BaseParser implements IParser {
|
||||||
if (shouldAddSubsettedTag()) {
|
if (shouldAddSubsettedTag()) {
|
||||||
IBaseCoding coding = metaValue.addTag();
|
IBaseCoding coding = metaValue.addTag();
|
||||||
coding.setCode(Constants.TAG_SUBSETTED_CODE);
|
coding.setCode(Constants.TAG_SUBSETTED_CODE);
|
||||||
coding.setSystem(Constants.TAG_SUBSETTED_SYSTEM);
|
coding.setSystem(getSubsettedCodeSystem());
|
||||||
coding.setDisplay(subsetDescription());
|
coding.setDisplay(subsetDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -785,6 +785,14 @@ public abstract class BaseParser implements IParser {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getSubsettedCodeSystem() {
|
||||||
|
if (myContext.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.R4)) {
|
||||||
|
return Constants.TAG_SUBSETTED_SYSTEM_R4;
|
||||||
|
} else {
|
||||||
|
return Constants.TAG_SUBSETTED_SYSTEM_DSTU3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setDontEncodeElements(Set<String> theDontEncodeElements) {
|
public void setDontEncodeElements(Set<String> theDontEncodeElements) {
|
||||||
myDontEncodeElementsIncludesStars = false;
|
myDontEncodeElementsIncludesStars = false;
|
||||||
|
|
|
@ -1286,9 +1286,7 @@ class ParserState<T> {
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
myInstance.setValueAsString(theValue);
|
myInstance.setValueAsString(theValue);
|
||||||
} catch (DataFormatException e) {
|
} catch (DataFormatException | IllegalArgumentException e) {
|
||||||
myErrorHandler.invalidValue(null, theValue, e.getMessage());
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
myErrorHandler.invalidValue(null, theValue, e.getMessage());
|
myErrorHandler.invalidValue(null, theValue, e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,7 +182,8 @@ public class Constants {
|
||||||
public static final int STATUS_HTTP_500_INTERNAL_ERROR = 500;
|
public static final int STATUS_HTTP_500_INTERNAL_ERROR = 500;
|
||||||
public static final int STATUS_HTTP_501_NOT_IMPLEMENTED = 501;
|
public static final int STATUS_HTTP_501_NOT_IMPLEMENTED = 501;
|
||||||
public static final String TAG_SUBSETTED_CODE = "SUBSETTED";
|
public static final String TAG_SUBSETTED_CODE = "SUBSETTED";
|
||||||
public static final String TAG_SUBSETTED_SYSTEM = "http://hl7.org/fhir/v3/ObservationValue";
|
public static final String TAG_SUBSETTED_SYSTEM_DSTU3 = "http://hl7.org/fhir/v3/ObservationValue";
|
||||||
|
public static final String TAG_SUBSETTED_SYSTEM_R4 = "http://terminology.hl7.org/CodeSystem/v3-ObservationValue";
|
||||||
public static final String URL_TOKEN_HISTORY = "_history";
|
public static final String URL_TOKEN_HISTORY = "_history";
|
||||||
public static final String URL_TOKEN_METADATA = "metadata";
|
public static final String URL_TOKEN_METADATA = "metadata";
|
||||||
public static final String OO_INFOSTATUS_PROCESSING = "processing";
|
public static final String OO_INFOSTATUS_PROCESSING = "processing";
|
||||||
|
|
|
@ -89,7 +89,15 @@ public enum RestSearchParameterTypeEnum {
|
||||||
*/
|
*/
|
||||||
HAS("string", "http://hl7.org/fhir/search-param-type"),
|
HAS("string", "http://hl7.org/fhir/search-param-type"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Code Value: <b>number</b>
|
||||||
|
*
|
||||||
|
* Search parameter SHALL be a number (a whole number, or a decimal).
|
||||||
|
*/
|
||||||
|
SPECIAL("special", "http://hl7.org/fhir/search-param-type"),
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identifier for this Value Set:
|
* Identifier for this Value Set:
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
package ca.uhn.fhir.rest.gclient;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Core Library
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class SpecialClientParam extends BaseClientParam implements IParam {
|
||||||
|
|
||||||
|
private final String myParamName;
|
||||||
|
|
||||||
|
public SpecialClientParam(String theParamName) {
|
||||||
|
myParamName = theParamName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getParamName() {
|
||||||
|
return myParamName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package ca.uhn.fhir.rest.param;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.util.CoverageIgnore;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Core Library
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
public class SpecialAndListParam extends BaseAndListParam<SpecialOrListParam> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
SpecialOrListParam newInstance() {
|
||||||
|
return new SpecialOrListParam();
|
||||||
|
}
|
||||||
|
|
||||||
|
@CoverageIgnore
|
||||||
|
@Override
|
||||||
|
public SpecialAndListParam addAnd(SpecialOrListParam theValue) {
|
||||||
|
addValue(theValue);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package ca.uhn.fhir.rest.param;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.util.CoverageIgnore;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Core Library
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
public class SpecialOrListParam extends BaseOrListParam<SpecialOrListParam, SpecialParam> {
|
||||||
|
|
||||||
|
@CoverageIgnore
|
||||||
|
@Override
|
||||||
|
SpecialParam newInstance() {
|
||||||
|
return new SpecialParam();
|
||||||
|
}
|
||||||
|
|
||||||
|
@CoverageIgnore
|
||||||
|
@Override
|
||||||
|
public SpecialOrListParam addOr(SpecialParam theParameter) {
|
||||||
|
add(theParameter);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
package ca.uhn.fhir.rest.param;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Core Library
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.model.primitive.UriDt;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||||
|
|
||||||
|
public class SpecialParam extends BaseParam /*implements IQueryParameterType*/ {
|
||||||
|
|
||||||
|
private String myValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public SpecialParam() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String doGetQueryParameterQualifier() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
String doGetValueAsQueryToken(FhirContext theContext) {
|
||||||
|
return ParameterUtil.escape(getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theParameter) {
|
||||||
|
setValue(ParameterUtil.unescape(theParameter));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value for the token (generally the value to the right of the
|
||||||
|
* vertical bar on the URL)
|
||||||
|
*/
|
||||||
|
public String getValue() {
|
||||||
|
return myValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValueNotNull() {
|
||||||
|
return defaultString(myValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return StringUtils.isEmpty(myValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public SpecialParam setValue(String theValue) {
|
||||||
|
myValue = theValue;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
|
||||||
|
builder.append("value", getValue());
|
||||||
|
if (getMissing() != null) {
|
||||||
|
builder.append(":missing", getMissing());
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String toSystemValue(UriDt theSystem) {
|
||||||
|
return theSystem.getValueAsString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -160,7 +160,7 @@ public abstract class BaseServerResponseException extends RuntimeException {
|
||||||
* The underlying cause exception
|
* The underlying cause exception
|
||||||
*/
|
*/
|
||||||
public BaseServerResponseException(int theStatusCode, Throwable theCause) {
|
public BaseServerResponseException(int theStatusCode, Throwable theCause) {
|
||||||
super(theCause.toString(), theCause);
|
super(theCause.getMessage(), theCause);
|
||||||
myStatusCode = theStatusCode;
|
myStatusCode = theStatusCode;
|
||||||
myBaseOperationOutcome = null;
|
myBaseOperationOutcome = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,10 +44,23 @@ public class InvalidRequestException extends BaseServerResponseException {
|
||||||
public static final int STATUS_CODE = Constants.STATUS_HTTP_400_BAD_REQUEST;
|
public static final int STATUS_CODE = Constants.STATUS_HTTP_400_BAD_REQUEST;
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
public InvalidRequestException(String theMessage) {
|
public InvalidRequestException(String theMessage) {
|
||||||
super(STATUS_CODE, theMessage);
|
super(STATUS_CODE, theMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public InvalidRequestException(String theMessage, Throwable theCause) {
|
||||||
|
super(STATUS_CODE, theMessage, theCause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
public InvalidRequestException(Throwable theCause) {
|
public InvalidRequestException(Throwable theCause) {
|
||||||
super(STATUS_CODE, theCause);
|
super(STATUS_CODE, theCause);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhir.util;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* #%L
|
* #%L
|
||||||
|
@ -24,6 +25,8 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
*/
|
*/
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.hl7.fhir.instance.model.api.*;
|
import org.hl7.fhir.instance.model.api.*;
|
||||||
|
@ -40,6 +43,7 @@ import ca.uhn.fhir.parser.DataFormatException;
|
||||||
|
|
||||||
public class FhirTerser {
|
public class FhirTerser {
|
||||||
|
|
||||||
|
public static final Pattern COMPARTMENT_MATCHER_PATH = Pattern.compile("([a-zA-Z.]+)\\.where\\(resolve\\(\\) is ([a-zA-Z]+)\\)");
|
||||||
private FhirContext myContext;
|
private FhirContext myContext;
|
||||||
|
|
||||||
public FhirTerser(FhirContext theContext) {
|
public FhirTerser(FhirContext theContext) {
|
||||||
|
@ -364,8 +368,26 @@ public class FhirTerser {
|
||||||
List<RuntimeSearchParam> params = sourceDef.getSearchParamsForCompartmentName(theCompartmentName);
|
List<RuntimeSearchParam> params = sourceDef.getSearchParamsForCompartmentName(theCompartmentName);
|
||||||
for (RuntimeSearchParam nextParam : params) {
|
for (RuntimeSearchParam nextParam : params) {
|
||||||
for (String nextPath : nextParam.getPathsSplit()) {
|
for (String nextPath : nextParam.getPathsSplit()) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DSTU3 and before just defined compartments as being (e.g.) named
|
||||||
|
* Patient with a path like CarePlan.subject
|
||||||
|
*
|
||||||
|
* R4 uses a fancier format like CarePlan.subject.where(resolve() is Patient)
|
||||||
|
*
|
||||||
|
* The following Regex is a hack to make that efficient at runtime.
|
||||||
|
*/
|
||||||
|
String wantType = null;
|
||||||
|
Pattern pattern = COMPARTMENT_MATCHER_PATH;
|
||||||
|
Matcher matcher = pattern.matcher(nextPath);
|
||||||
|
if (matcher.matches()) {
|
||||||
|
nextPath = matcher.group(1);
|
||||||
|
wantType = matcher.group(2);
|
||||||
|
}
|
||||||
|
|
||||||
for (IBaseReference nextValue : getValues(theSource, nextPath, IBaseReference.class)) {
|
for (IBaseReference nextValue : getValues(theSource, nextPath, IBaseReference.class)) {
|
||||||
String nextRef = nextValue.getReferenceElement().toUnqualifiedVersionless().getValue();
|
IIdType nextTargetId = nextValue.getReferenceElement();
|
||||||
|
String nextRef = nextTargetId.toUnqualifiedVersionless().getValue();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the reference isn't an explicit resource ID, but instead is just
|
* If the reference isn't an explicit resource ID, but instead is just
|
||||||
|
@ -374,7 +396,7 @@ public class FhirTerser {
|
||||||
*/
|
*/
|
||||||
if (isBlank(nextRef) && nextValue.getResource() != null) {
|
if (isBlank(nextRef) && nextValue.getResource() != null) {
|
||||||
IBaseResource nextTarget = nextValue.getResource();
|
IBaseResource nextTarget = nextValue.getResource();
|
||||||
IIdType nextTargetId = nextTarget.getIdElement().toUnqualifiedVersionless();
|
nextTargetId = nextTarget.getIdElement().toUnqualifiedVersionless();
|
||||||
if (!nextTargetId.hasResourceType()) {
|
if (!nextTargetId.hasResourceType()) {
|
||||||
String resourceType = myContext.getResourceDefinition(nextTarget).getName();
|
String resourceType = myContext.getResourceDefinition(nextTarget).getName();
|
||||||
nextTargetId.setParts(null, resourceType, nextTargetId.getIdPart(), null);
|
nextTargetId.setParts(null, resourceType, nextTargetId.getIdPart(), null);
|
||||||
|
@ -382,6 +404,12 @@ public class FhirTerser {
|
||||||
nextRef = nextTargetId.getValue();
|
nextRef = nextTargetId.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isNotBlank(wantType)) {
|
||||||
|
if (!nextTargetId.getResourceType().equals(wantType)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (wantRef.equals(nextRef)) {
|
if (wantRef.equals(nextRef)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.r4.model.CodeSystem;
|
import org.hl7.fhir.r4.model.CodeSystem;
|
||||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||||
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
|
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
|
||||||
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionComponent;
|
import org.hl7.fhir.r4.terminologies.ValueSetExpander;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -39,7 +39,7 @@ public class LoadingValidationSupportR4 implements org.hl7.fhir.r4.hapi.ctx.IVal
|
||||||
private FhirContext myCtx = FhirContext.forR4();
|
private FhirContext myCtx = FhirContext.forR4();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
public ValueSetExpander.ValueSetExpansionOutcome expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,9 +98,9 @@ public class VersionedApiConverterInterceptor extends InterceptorAdapter {
|
||||||
IBaseResource converted = null;
|
IBaseResource converted = null;
|
||||||
try {
|
try {
|
||||||
if (wantVersion == FhirVersionEnum.R4 && haveVersion == FhirVersionEnum.DSTU3) {
|
if (wantVersion == FhirVersionEnum.R4 && haveVersion == FhirVersionEnum.DSTU3) {
|
||||||
converted = myVersionConvertor_30_40.convertResource(toDstu3(responseResource));
|
converted = myVersionConvertor_30_40.convertResource(toDstu3(responseResource), true);
|
||||||
} else if (wantVersion == FhirVersionEnum.DSTU3 && haveVersion == FhirVersionEnum.R4) {
|
} else if (wantVersion == FhirVersionEnum.DSTU3 && haveVersion == FhirVersionEnum.R4) {
|
||||||
converted = myVersionConvertor_30_40.convertResource(toR4(responseResource));
|
converted = myVersionConvertor_30_40.convertResource(toR4(responseResource), true);
|
||||||
} else if (wantVersion == FhirVersionEnum.DSTU2 && haveVersion == FhirVersionEnum.R4) {
|
} else if (wantVersion == FhirVersionEnum.DSTU2 && haveVersion == FhirVersionEnum.R4) {
|
||||||
converted = myVersionConvertor_10_40.convertResource(toR4(responseResource));
|
converted = myVersionConvertor_10_40.convertResource(toR4(responseResource));
|
||||||
} else if (wantVersion == FhirVersionEnum.R4 && haveVersion == FhirVersionEnum.DSTU2) {
|
} else if (wantVersion == FhirVersionEnum.R4 && haveVersion == FhirVersionEnum.DSTU2) {
|
||||||
|
|
|
@ -1,28 +1,69 @@
|
||||||
package org.hl7.fhir.convertors;
|
package org.hl7.fhir.convertors;
|
||||||
|
|
||||||
/*-
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
* #%L
|
|
||||||
* HAPI FHIR - Converter
|
public class VersionConvertorConstants {
|
||||||
* %%
|
|
||||||
* Copyright (C) 2014 - 2018 University Health Network
|
public final static String IG_DEPENDSON_PACKAGE_EXTENSION = "http://hl7.org/fhir/4.0/StructureDefinition/extension-ImplentationGuide.dependency.packageId";
|
||||||
* %%
|
public final static String IG_DEPENDSON_VERSION_EXTENSION = "http://hl7.org/fhir/4.0/StructureDefinition/extension-ImplentationGuide.dependency.version";
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
public final static String MODIFIER_REASON_EXTENSION = "http://hl7.org/fhir/4.0/StructureDefinition/extension-ElementDefinition.isModifierReason";
|
||||||
* you may not use this file except in compliance with the License.
|
public final static String MODIFIER_REASON_LEGACY = "No Modifier Reason provideed in previous versions of FHIR";
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
public static String refToVS(String url) {
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
if (url == null)
|
||||||
*
|
return null;
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
if (url.equals("http://www.genenames.org"))
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
return "http://hl7.org/fhir/ValueSet/genenames";
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
else if (url.equals("http://varnomen.hgvs.org/"))
|
||||||
* See the License for the specific language governing permissions and
|
return "http://hl7.org/fhir/ValueSet/variants";
|
||||||
* limitations under the License.
|
else if (url.equals("http://www.ncbi.nlm.nih.gov/nuccore?db=nuccore"))
|
||||||
* #L%
|
return "http://hl7.org/fhir/ValueSet/ref-sequences";
|
||||||
*/
|
else if (url.equals("http://www.ensembl.org/"))
|
||||||
|
return "http://hl7.org/fhir/ValueSet/ensembl";
|
||||||
|
else if (url.equals("http://www.ncbi.nlm.nih.gov/clinvar/variation"))
|
||||||
public class VersionConvertorConstants {
|
return "http://hl7.org/fhir/ValueSet/clinvar";
|
||||||
|
else if (url.equals("http://cancer.sanger.ac.uk/cancergenome/projects/cosmic/"))
|
||||||
public final static String MODIFIER_REASON_EXTENSION = "http://hl7.org/fhir/tooling/StructureDefinition/r4ModifierReason";
|
return "http://hl7.org/fhir/ValueSet/cosmic";
|
||||||
public final static String MODIFIER_REASON_LEGACY = "No Modifier Reason provideed in previous versions of FHIR";
|
else if (url.equals("http://www.ncbi.nlm.nih.gov/projects/SNP/"))
|
||||||
}
|
return "http://hl7.org/fhir/ValueSet/bbsnp";
|
||||||
|
else if (url.equals("http://www.sequenceontology.org/"))
|
||||||
|
return "http://hl7.org/fhir/ValueSet/sequenceontology";
|
||||||
|
else if (url.equals("http://www.ebi.ac.uk/"))
|
||||||
|
return "http://hl7.org/fhir/ValueSet/allelename";
|
||||||
|
else if (url.equals("https://www.iso.org/iso-4217-currency-codes.html"))
|
||||||
|
return "http://hl7.org/fhir/ValueSet/currencies";
|
||||||
|
else if (url.equals("http://www.rfc-editor.org/bcp/bcp13.txt"))
|
||||||
|
return "http://hl7.org/fhir/ValueSet/mimetypes";
|
||||||
|
else
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String vsToRef(String url) {
|
||||||
|
if (url == null)
|
||||||
|
return null;
|
||||||
|
if (url.equals("http://hl7.org/fhir/ValueSet/genenames"))
|
||||||
|
return "http://www.genenames.org";
|
||||||
|
else if (url.equals("http://hl7.org/fhir/ValueSet/variants"))
|
||||||
|
return "http://varnomen.hgvs.org/";
|
||||||
|
else if (url.equals("http://hl7.org/fhir/ValueSet/ref-sequences"))
|
||||||
|
return "http://www.ncbi.nlm.nih.gov/nuccore?db=nuccore";
|
||||||
|
else if (url.equals("http://hl7.org/fhir/ValueSet/ensembl"))
|
||||||
|
return "http://www.ensembl.org/";
|
||||||
|
else if (url.equals("http://hl7.org/fhir/ValueSet/clinvar"))
|
||||||
|
return "http://www.ncbi.nlm.nih.gov/clinvar/variation";
|
||||||
|
else if (url.equals("http://hl7.org/fhir/ValueSet/cosmic"))
|
||||||
|
return "http://cancer.sanger.ac.uk/cancergenome/projects/cosmic/";
|
||||||
|
else if (url.equals("http://hl7.org/fhir/ValueSet/bbsnp"))
|
||||||
|
return "http://www.ncbi.nlm.nih.gov/projects/SNP/";
|
||||||
|
else if (url.equals("http://hl7.org/fhir/ValueSet/sequenceontology"))
|
||||||
|
return "http://www.sequenceontology.org/";
|
||||||
|
else if (url.equals("http://hl7.org/fhir/ValueSet/allelename"))
|
||||||
|
return "http://www.ebi.ac.uk/";
|
||||||
|
else if (url.equals("http://hl7.org/fhir/ValueSet/currencies"))
|
||||||
|
return "https://www.iso.org/iso-4217-currency-codes.html";
|
||||||
|
else if (url.equals("http://hl7.org/fhir/ValueSet/mimetypes"))
|
||||||
|
return "http://www.rfc-editor.org/bcp/bcp13.txt";
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -67,7 +67,7 @@ public class BaseR4Config extends BaseConfig {
|
||||||
|
|
||||||
// Don't strip versions in some places
|
// Don't strip versions in some places
|
||||||
ParserOptions parserOptions = retVal.getParserOptions();
|
ParserOptions parserOptions = retVal.getParserOptions();
|
||||||
parserOptions.setDontStripVersionsFromReferencesAtPaths("AuditEvent.entity.reference");
|
parserOptions.setDontStripVersionsFromReferencesAtPaths("AuditEvent.entity.what");
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
|
@ -388,7 +388,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
ResourceTable resource = myResourceTableDao.findById(theResourceId).orElseThrow(IllegalStateException::new);
|
ResourceTable resource = myResourceTableDao.findById(theResourceId).orElseThrow(IllegalStateException::new);
|
||||||
|
|
||||||
ResourceHistoryTable currentVersion = myResourceHistoryTableDao.findForIdAndVersion(resource.getId(), resource.getVersion());
|
ResourceHistoryTable currentVersion = myResourceHistoryTableDao.findForIdAndVersion(resource.getId(), resource.getVersion());
|
||||||
expungeHistoricalVersion(currentVersion.getId());
|
if (currentVersion != null) {
|
||||||
|
expungeHistoricalVersion(currentVersion.getId());
|
||||||
|
}
|
||||||
|
|
||||||
ourLog.info("Deleting current version of resource {}", resource.getIdDt().getValue());
|
ourLog.info("Deleting current version of resource {}", resource.getIdDt().getValue());
|
||||||
|
|
||||||
|
@ -2338,7 +2340,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
IResource res = (IResource) theResource;
|
IResource res = (IResource) theResource;
|
||||||
TagList tagList = ResourceMetadataKeyEnum.TAG_LIST.get(res);
|
TagList tagList = ResourceMetadataKeyEnum.TAG_LIST.get(res);
|
||||||
if (tagList != null) {
|
if (tagList != null) {
|
||||||
tag = tagList.getTag(Constants.TAG_SUBSETTED_SYSTEM, Constants.TAG_SUBSETTED_CODE);
|
tag = tagList.getTag(Constants.TAG_SUBSETTED_SYSTEM_DSTU3, Constants.TAG_SUBSETTED_CODE);
|
||||||
totalMetaCount += tagList.size();
|
totalMetaCount += tagList.size();
|
||||||
}
|
}
|
||||||
List<IdDt> profileList = ResourceMetadataKeyEnum.PROFILES.get(res);
|
List<IdDt> profileList = ResourceMetadataKeyEnum.PROFILES.get(res);
|
||||||
|
@ -2347,7 +2349,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
IAnyResource res = (IAnyResource) theResource;
|
IAnyResource res = (IAnyResource) theResource;
|
||||||
tag = res.getMeta().getTag(Constants.TAG_SUBSETTED_SYSTEM, Constants.TAG_SUBSETTED_CODE);
|
tag = res.getMeta().getTag(Constants.TAG_SUBSETTED_SYSTEM_DSTU3, Constants.TAG_SUBSETTED_CODE);
|
||||||
totalMetaCount += res.getMeta().getTag().size();
|
totalMetaCount += res.getMeta().getTag().size();
|
||||||
totalMetaCount += res.getMeta().getProfile().size();
|
totalMetaCount += res.getMeta().getProfile().size();
|
||||||
totalMetaCount += res.getMeta().getSecurity().size();
|
totalMetaCount += res.getMeta().getSecurity().size();
|
||||||
|
|
|
@ -41,6 +41,7 @@ import java.util.regex.Pattern;
|
||||||
public abstract class BaseSearchParamExtractor implements ISearchParamExtractor {
|
public abstract class BaseSearchParamExtractor implements ISearchParamExtractor {
|
||||||
|
|
||||||
public static final Pattern SPLIT = Pattern.compile("\\||( or )");
|
public static final Pattern SPLIT = Pattern.compile("\\||( or )");
|
||||||
|
public static final Pattern SPLIT_R4 = Pattern.compile("\\|");
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseSearchParamExtractor.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseSearchParamExtractor.class);
|
||||||
@Autowired
|
@Autowired
|
||||||
private FhirContext myContext;
|
private FhirContext myContext;
|
||||||
|
|
|
@ -1186,6 +1186,10 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
BaseCodingDt id = (BaseCodingDt) theParameter;
|
BaseCodingDt id = (BaseCodingDt) theParameter;
|
||||||
system = id.getSystemElement().getValueAsString();
|
system = id.getSystemElement().getValueAsString();
|
||||||
code = (id.getCodeElement().getValue());
|
code = (id.getCodeElement().getValue());
|
||||||
|
} else if (theParameter instanceof NumberParam) {
|
||||||
|
NumberParam number = (NumberParam) theParameter;
|
||||||
|
system = null;
|
||||||
|
code = number.getValueAsQueryToken(myContext);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Invalid token type: " + theParameter.getClass());
|
throw new IllegalArgumentException("Invalid token type: " + theParameter.getClass());
|
||||||
}
|
}
|
||||||
|
@ -2082,11 +2086,16 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
* SearchParameters can declare paths on multiple resources
|
* SearchParameters can declare paths on multiple resources
|
||||||
* types. Here we only want the ones that actually apply.
|
* types. Here we only want the ones that actually apply.
|
||||||
*/
|
*/
|
||||||
for (Iterator<String> iter = path.iterator(); iter.hasNext(); ) {
|
path = new ArrayList<>(path);
|
||||||
if (!iter.next().startsWith(theResourceType + ".")) {
|
|
||||||
iter.remove();
|
for (int i = 0; i < path.size(); i++) {
|
||||||
|
String nextPath = trim(path.get(i));
|
||||||
|
if (!nextPath.contains(theResourceType + ".")) {
|
||||||
|
path.remove(i);
|
||||||
|
i--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return theFrom.get("mySourcePath").in(path);
|
return theFrom.get("mySourcePath").in(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.r4.model.*;
|
import org.hl7.fhir.r4.model.*;
|
||||||
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
|
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
|
||||||
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionComponent;
|
import org.hl7.fhir.r4.terminologies.ValueSetExpander;
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
@ -66,7 +66,7 @@ public class JpaValidationSupportR4 implements IJpaValidationSupportR4, Applicat
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(value = TxType.SUPPORTS)
|
@Transactional(value = TxType.SUPPORTS)
|
||||||
public ValueSetExpansionComponent expandValueSet(FhirContext theCtx, ConceptSetComponent theInclude) {
|
public ValueSetExpander.ValueSetExpansionOutcome expandValueSet(FhirContext theCtx, ConceptSetComponent theInclude) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.dao.r4;
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -31,6 +31,7 @@ import com.google.common.annotations.VisibleForTesting;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.hl7.fhir.exceptions.FHIRException;
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
|
import org.hl7.fhir.exceptions.PathEngineException;
|
||||||
import org.hl7.fhir.instance.model.api.IBase;
|
import org.hl7.fhir.instance.model.api.IBase;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
@ -48,14 +49,16 @@ import javax.measure.unit.NonSI;
|
||||||
import javax.measure.unit.Unit;
|
import javax.measure.unit.Unit;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
import static org.apache.commons.lang3.StringUtils.trim;
|
||||||
|
|
||||||
public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements ISearchParamExtractor {
|
public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements ISearchParamExtractor {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParamExtractorR4.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParamExtractorR4.class);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private org.hl7.fhir.r4.hapi.ctx.IValidationSupport myValidationSupport;
|
private org.hl7.fhir.r4.hapi.ctx.IValidationSupport myValidationSupport;
|
||||||
|
|
||||||
|
@ -108,10 +111,11 @@ public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements
|
||||||
public List<PathAndRef> extractResourceLinks(IBaseResource theResource, RuntimeSearchParam theNextSpDef) {
|
public List<PathAndRef> extractResourceLinks(IBaseResource theResource, RuntimeSearchParam theNextSpDef) {
|
||||||
ArrayList<PathAndRef> retVal = new ArrayList<>();
|
ArrayList<PathAndRef> retVal = new ArrayList<>();
|
||||||
|
|
||||||
String[] nextPathsSplit = SPLIT.split(theNextSpDef.getPath());
|
String[] nextPathsSplit = SPLIT_R4.split(theNextSpDef.getPath());
|
||||||
for (String path : nextPathsSplit) {
|
for (String path : nextPathsSplit) {
|
||||||
path = path.trim();
|
path = path.trim();
|
||||||
if (isNotBlank(path)) {
|
if (isNotBlank(path)) {
|
||||||
|
|
||||||
for (Object next : extractValues(path, theResource)) {
|
for (Object next : extractValues(path, theResource)) {
|
||||||
retVal.add(new PathAndRef(path, next));
|
retVal.add(new PathAndRef(path, next));
|
||||||
}
|
}
|
||||||
|
@ -447,7 +451,7 @@ public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements
|
||||||
addSearchTerm(theEntity, retVal, nextSpName, value.toPlainString());
|
addSearchTerm(theEntity, retVal, nextSpName, value.toPlainString());
|
||||||
}
|
}
|
||||||
} else if (nextObject instanceof Range) {
|
} else if (nextObject instanceof Range) {
|
||||||
SimpleQuantity low = ((Range) nextObject).getLow();
|
Quantity low = ((Range) nextObject).getLow();
|
||||||
if (low != null) {
|
if (low != null) {
|
||||||
BigDecimal value = low.getValue();
|
BigDecimal value = low.getValue();
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
|
@ -708,9 +712,10 @@ public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements
|
||||||
protected List<Object> extractValues(String thePaths, IBaseResource theResource) {
|
protected List<Object> extractValues(String thePaths, IBaseResource theResource) {
|
||||||
IWorkerContext worker = new org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext(getContext(), myValidationSupport);
|
IWorkerContext worker = new org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext(getContext(), myValidationSupport);
|
||||||
FHIRPathEngine fp = new FHIRPathEngine(worker);
|
FHIRPathEngine fp = new FHIRPathEngine(worker);
|
||||||
|
fp.setHostServices(new SearchParamExtractorR4HostServices());
|
||||||
|
|
||||||
List<Object> values = new ArrayList<>();
|
List<Object> values = new ArrayList<>();
|
||||||
String[] nextPathsSplit = SPLIT.split(thePaths);
|
String[] nextPathsSplit = SPLIT_R4.split(thePaths);
|
||||||
for (String nextPath : nextPathsSplit) {
|
for (String nextPath : nextPathsSplit) {
|
||||||
List<Base> allValues;
|
List<Base> allValues;
|
||||||
try {
|
try {
|
||||||
|
@ -748,4 +753,88 @@ public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class SearchParamExtractorR4HostServices implements FHIRPathEngine.IEvaluationContext {
|
||||||
|
@Override
|
||||||
|
public Base resolveConstant(Object appContext, String name) throws PathEngineException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeDetails resolveConstantType(Object appContext, String name) throws PathEngineException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean log(String argument, List<Base> focus) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FunctionDetails resolveFunction(String functionName) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeDetails checkFunction(Object appContext, String functionName, List<TypeDetails> parameters) throws PathEngineException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Base> executeFunction(Object appContext, String functionName, List<List<Base>> parameters) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Base> myResourceTypeToStub = Collections.synchronizedMap(new HashMap<>());
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Base resolveReference(Object theAppContext, String theUrl) throws FHIRException {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When we're doing resolution within the SearchParamExtractor, if we want
|
||||||
|
* to do a resolve() it's just to check the type, so there is no point
|
||||||
|
* going through the heavyweight test. We can just return a stub and
|
||||||
|
* that's good enough since we're just doing something like
|
||||||
|
* Encounter.patient.where(resolve() is Patient)
|
||||||
|
*/
|
||||||
|
IdType url = new IdType(theUrl);
|
||||||
|
Base retVal = null;
|
||||||
|
if (isNotBlank(url.getResourceType())) {
|
||||||
|
|
||||||
|
retVal = myResourceTypeToStub.get(url.getResourceType());
|
||||||
|
if (retVal != null) {
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceType resourceType = ResourceType.fromCode(url.getResourceType());
|
||||||
|
if (resourceType != null) {
|
||||||
|
retVal = new Resource(){
|
||||||
|
@Override
|
||||||
|
public Resource copy() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceType getResourceType() {
|
||||||
|
return resourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String fhirType() {
|
||||||
|
return url.getResourceType();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
myResourceTypeToStub.put(url.getResourceType(), retVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean conformsToProfile(Object appContext, Base item, String url) throws FHIRException {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,11 +83,12 @@ public class ResourceIndexedSearchParamQuantity extends BaseResourceIndexedSearc
|
||||||
private Long myHashIdentity;
|
private Long myHashIdentity;
|
||||||
|
|
||||||
public ResourceIndexedSearchParamQuantity() {
|
public ResourceIndexedSearchParamQuantity() {
|
||||||
// nothing
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ResourceIndexedSearchParamQuantity(String theParamName, BigDecimal theValue, String theSystem, String theUnits) {
|
public ResourceIndexedSearchParamQuantity(String theParamName, BigDecimal theValue, String theSystem, String theUnits) {
|
||||||
|
this();
|
||||||
setParamName(theParamName);
|
setParamName(theParamName);
|
||||||
setSystem(theSystem);
|
setSystem(theSystem);
|
||||||
setValue(theValue);
|
setValue(theValue);
|
||||||
|
|
|
@ -39,6 +39,7 @@ import java.util.Date;
|
||||||
public class ResourceLink implements Serializable {
|
public class ResourceLink implements Serializable {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
public static final int SRC_PATH_LENGTH = 200;
|
||||||
|
|
||||||
@SequenceGenerator(name = "SEQ_RESLINK_ID", sequenceName = "SEQ_RESLINK_ID")
|
@SequenceGenerator(name = "SEQ_RESLINK_ID", sequenceName = "SEQ_RESLINK_ID")
|
||||||
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_RESLINK_ID")
|
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_RESLINK_ID")
|
||||||
|
@ -46,7 +47,7 @@ public class ResourceLink implements Serializable {
|
||||||
@Column(name = "PID")
|
@Column(name = "PID")
|
||||||
private Long myId;
|
private Long myId;
|
||||||
|
|
||||||
@Column(name = "SRC_PATH", length = 100, nullable = false)
|
@Column(name = "SRC_PATH", length = SRC_PATH_LENGTH, nullable = false)
|
||||||
private String mySourcePath;
|
private String mySourcePath;
|
||||||
|
|
||||||
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||||
|
|
|
@ -15,7 +15,7 @@ import org.hl7.fhir.r4.model.ConceptMap;
|
||||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||||
import org.hl7.fhir.r4.model.ValueSet;
|
import org.hl7.fhir.r4.model.ValueSet;
|
||||||
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
|
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
|
||||||
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionComponent;
|
import org.hl7.fhir.r4.terminologies.ValueSetExpander;
|
||||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
@ -142,10 +142,11 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvcImpl implements
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
public ValueSetExpander.ValueSetExpansionOutcome expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
||||||
ValueSet valueSetToExpand = new ValueSet();
|
ValueSet valueSetToExpand = new ValueSet();
|
||||||
valueSetToExpand.getCompose().addInclude(theInclude);
|
valueSetToExpand.getCompose().addInclude(theInclude);
|
||||||
return super.expandValueSet(valueSetToExpand).getExpansion();
|
ValueSet expanded = super.expandValueSet(valueSetToExpand);
|
||||||
|
return new ValueSetExpander.ValueSetExpansionOutcome(expanded);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -385,7 +385,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
||||||
p.addName().addFamily("Hello");
|
p.addName().addFamily("Hello");
|
||||||
|
|
||||||
TagList tl = new TagList();
|
TagList tl = new TagList();
|
||||||
tl.addTag(Constants.TAG_SUBSETTED_SYSTEM, Constants.TAG_SUBSETTED_CODE);
|
tl.addTag(Constants.TAG_SUBSETTED_SYSTEM_DSTU3, Constants.TAG_SUBSETTED_CODE);
|
||||||
ResourceMetadataKeyEnum.TAG_LIST.put(p, tl);
|
ResourceMetadataKeyEnum.TAG_LIST.put(p, tl);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -653,7 +653,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
||||||
p.addIdentifier().setSystem("urn:system").setValue("testCreateTextIdFails");
|
p.addIdentifier().setSystem("urn:system").setValue("testCreateTextIdFails");
|
||||||
p.addName().setFamily("Hello");
|
p.addName().setFamily("Hello");
|
||||||
|
|
||||||
p.getMeta().addTag().setSystem(Constants.TAG_SUBSETTED_SYSTEM).setCode(Constants.TAG_SUBSETTED_CODE);
|
p.getMeta().addTag().setSystem(Constants.TAG_SUBSETTED_SYSTEM_DSTU3).setCode(Constants.TAG_SUBSETTED_CODE);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
myPatientDao.create(p, mySrd);
|
myPatientDao.create(p, mySrd);
|
||||||
|
|
|
@ -2,7 +2,7 @@ package ca.uhn.fhir.jpa.dao.dstu3;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.hamcrest.Matchers.*;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.reset;
|
import static org.mockito.Mockito.reset;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
|
|
@ -136,6 +136,9 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("myImmunizationRecommendationDaoR4")
|
@Qualifier("myImmunizationRecommendationDaoR4")
|
||||||
protected IFhirResourceDao<ImmunizationRecommendation> myImmunizationRecommendationDao;
|
protected IFhirResourceDao<ImmunizationRecommendation> myImmunizationRecommendationDao;
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("myRiskAssessmentDaoR4")
|
||||||
|
protected IFhirResourceDao<RiskAssessment> myRiskAssessmentDao;
|
||||||
protected IServerInterceptor myInterceptor;
|
protected IServerInterceptor myInterceptor;
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("myLocationDaoR4")
|
@Qualifier("myLocationDaoR4")
|
||||||
|
|
|
@ -382,7 +382,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
||||||
map.setLoadSynchronous(true);
|
map.setLoadSynchronous(true);
|
||||||
map.add("reason", new ReferenceParam(conditionId));
|
map.add("reason", new ReferenceParam(conditionId));
|
||||||
List<String> results = toUnqualifiedVersionlessIdValues(myMedicationRequestDao.search(map));
|
List<String> results = toUnqualifiedVersionlessIdValues(myMedicationRequestDao.search(map));
|
||||||
assertThat(results, contains(mrId));
|
assertThat(results.toString(), results, contains(mrId));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -303,6 +303,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
||||||
* Per message from David Hay on Skype
|
* Per message from David Hay on Skype
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore
|
||||||
public void testEverythingWithLargeSet() throws Exception {
|
public void testEverythingWithLargeSet() throws Exception {
|
||||||
myFhirCtx.setParserErrorHandler(new StrictErrorHandler());
|
myFhirCtx.setParserErrorHandler(new StrictErrorHandler());
|
||||||
|
|
||||||
|
@ -583,40 +584,40 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIndexNoDuplicatesNumber() {
|
public void testIndexNoDuplicatesNumber() {
|
||||||
final ImmunizationRecommendation res = new ImmunizationRecommendation();
|
final RiskAssessment res = new RiskAssessment();
|
||||||
res.addRecommendation().setDoseNumber(new PositiveIntType(1));
|
res.addPrediction().setProbability(new DecimalType("1.0"));
|
||||||
res.addRecommendation().setDoseNumber(new PositiveIntType(1));
|
res.addPrediction().setProbability(new DecimalType("1.0"));
|
||||||
res.addRecommendation().setDoseNumber(new PositiveIntType(1));
|
res.addPrediction().setProbability(new DecimalType("1.0"));
|
||||||
res.addRecommendation().setDoseNumber(new PositiveIntType(2));
|
res.addPrediction().setProbability(new DecimalType("2.0"));
|
||||||
res.addRecommendation().setDoseNumber(new PositiveIntType(2));
|
res.addPrediction().setProbability(new DecimalType("2.0"));
|
||||||
res.addRecommendation().setDoseNumber(new PositiveIntType(2));
|
res.addPrediction().setProbability(new DecimalType("2.0"));
|
||||||
|
res.addPrediction().setProbability(new DecimalType("2.0"));
|
||||||
|
|
||||||
IIdType id = myImmunizationRecommendationDao.create(res, mySrd).getId().toUnqualifiedVersionless();
|
IIdType id = myRiskAssessmentDao.create(res, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
List<IIdType> actual = toUnqualifiedVersionlessIds(myImmunizationRecommendationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(ImmunizationRecommendation.SP_DOSE_NUMBER, new NumberParam("1"))));
|
List<IIdType> actual = toUnqualifiedVersionlessIds(myRiskAssessmentDao.search(new SearchParameterMap().setLoadSynchronous(true).add(RiskAssessment.SP_PROBABILITY, new NumberParam("1.0"))));
|
||||||
assertThat(actual, contains(id));
|
assertThat(actual, contains(id));
|
||||||
|
actual = toUnqualifiedVersionlessIds(myRiskAssessmentDao.search(new SearchParameterMap().setLoadSynchronous(true).add(RiskAssessment.SP_PROBABILITY, new NumberParam("99.0"))));
|
||||||
|
assertThat(actual, empty());
|
||||||
|
|
||||||
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
||||||
@Override
|
@Override
|
||||||
protected void doInTransactionWithoutResult(TransactionStatus status) {
|
protected void doInTransactionWithoutResult(TransactionStatus status) {
|
||||||
ResourceTable resource = myResourceTableDao.findAll().iterator().next();
|
ResourceTable resource = myResourceTableDao.findAll().iterator().next();
|
||||||
assertEquals("ImmunizationRecommendation", resource.getResourceType());
|
assertEquals("RiskAssessment", resource.getResourceType());
|
||||||
|
|
||||||
Class<ResourceIndexedSearchParamNumber> type = ResourceIndexedSearchParamNumber.class;
|
Class<ResourceIndexedSearchParamNumber> type = ResourceIndexedSearchParamNumber.class;
|
||||||
List<ResourceIndexedSearchParamNumber> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
|
List<ResourceIndexedSearchParamNumber> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
|
||||||
ourLog.info(toStringMultiline(results));
|
ourLog.info(toStringMultiline(results));
|
||||||
|
|
||||||
ResourceIndexedSearchParamNumber expect0 = new ResourceIndexedSearchParamNumber(ImmunizationRecommendation.SP_DOSE_NUMBER, new BigDecimal("2.00"));
|
ResourceIndexedSearchParamNumber expect0 = new ResourceIndexedSearchParamNumber(RiskAssessment.SP_PROBABILITY, new BigDecimal("1.00"));
|
||||||
expect0.setResource(resource);
|
expect0.setResource(resource);
|
||||||
expect0.calculateHashes();
|
expect0.calculateHashes();
|
||||||
ResourceIndexedSearchParamNumber expect1 = new ResourceIndexedSearchParamNumber(ImmunizationRecommendation.SP_DOSE_SEQUENCE, null);
|
ResourceIndexedSearchParamNumber expect1 = new ResourceIndexedSearchParamNumber(RiskAssessment.SP_PROBABILITY, new BigDecimal("2.00"));
|
||||||
expect1.setResource(resource).setMissing(true);
|
expect1.setResource(resource);
|
||||||
expect1.calculateHashes();
|
expect1.calculateHashes();
|
||||||
ResourceIndexedSearchParamNumber expect2 = new ResourceIndexedSearchParamNumber(ImmunizationRecommendation.SP_DOSE_NUMBER, new BigDecimal("1.00"));
|
|
||||||
expect2.setResource(resource);
|
|
||||||
expect2.calculateHashes();
|
|
||||||
|
|
||||||
assertThat(results, containsInAnyOrder(expect0, expect1, expect2));
|
assertThat("Got: \"" + results.toString()+"\"", results, containsInAnyOrder(expect0, expect1));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1041,9 +1042,29 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testComponentQuantity() {
|
||||||
|
Observation o1 = new Observation();
|
||||||
|
o1.addComponent()
|
||||||
|
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://foo").setCode("code1")))
|
||||||
|
.setValue(new Quantity().setSystem("http://bar").setCode("code1").setValue(200));
|
||||||
|
o1.addComponent()
|
||||||
|
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://foo").setCode("code2")))
|
||||||
|
.setValue(new Quantity().setSystem("http://bar").setCode("code2").setValue(200));
|
||||||
|
IIdType id1 = myObservationDao.create(o1, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
String param = Observation.SP_COMPONENT_VALUE_QUANTITY;
|
||||||
|
|
||||||
|
{
|
||||||
|
QuantityParam v1 = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, 150, "http://bar", "code1");
|
||||||
|
SearchParameterMap map = new SearchParameterMap().setLoadSynchronous(true).add(param, v1);
|
||||||
|
IBundleProvider result = myObservationDao.search(map);
|
||||||
|
assertThat("Got: "+ toUnqualifiedVersionlessIdValues(result), toUnqualifiedVersionlessIdValues(result), containsInAnyOrder(id1.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSearchCompositeParamQuantity() {
|
public void testSearchCompositeParamQuantity() {
|
||||||
//@formatter:off
|
|
||||||
Observation o1 = new Observation();
|
Observation o1 = new Observation();
|
||||||
o1.addComponent()
|
o1.addComponent()
|
||||||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://foo").setCode("code1")))
|
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://foo").setCode("code1")))
|
||||||
|
@ -1061,35 +1082,35 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
||||||
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://foo").setCode("code3")))
|
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://foo").setCode("code3")))
|
||||||
.setValue(new Quantity().setSystem("http://bar").setCode("code2").setValue(200));
|
.setValue(new Quantity().setSystem("http://bar").setCode("code2").setValue(200));
|
||||||
IIdType id2 = myObservationDao.create(o2, mySrd).getId().toUnqualifiedVersionless();
|
IIdType id2 = myObservationDao.create(o2, mySrd).getId().toUnqualifiedVersionless();
|
||||||
//@formatter:on
|
|
||||||
|
|
||||||
String param = Observation.SP_COMPONENT_CODE_VALUE_QUANTITY;
|
String param = Observation.SP_COMPONENT_CODE_VALUE_QUANTITY;
|
||||||
|
|
||||||
{
|
{
|
||||||
TokenParam v0 = new TokenParam("http://foo", "code1");
|
TokenParam v0 = new TokenParam("http://foo", "code1");
|
||||||
QuantityParam v1 = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, 150, "http://bar", "code1");
|
QuantityParam v1 = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, 150, "http://bar", "code1");
|
||||||
CompositeParam<TokenParam, QuantityParam> val = new CompositeParam<TokenParam, QuantityParam>(v0, v1);
|
CompositeParam<TokenParam, QuantityParam> val = new CompositeParam<>(v0, v1);
|
||||||
IBundleProvider result = myObservationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(param, val));
|
SearchParameterMap map = new SearchParameterMap().setLoadSynchronous(true).add(param, val);
|
||||||
assertThat(toUnqualifiedVersionlessIdValues(result), containsInAnyOrder(id2.getValue()));
|
IBundleProvider result = myObservationDao.search(map);
|
||||||
|
assertThat("Got: "+ toUnqualifiedVersionlessIdValues(result), toUnqualifiedVersionlessIdValues(result), containsInAnyOrder(id2.getValue()));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
TokenParam v0 = new TokenParam("http://foo", "code1");
|
TokenParam v0 = new TokenParam("http://foo", "code1");
|
||||||
QuantityParam v1 = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, 50, "http://bar", "code1");
|
QuantityParam v1 = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, 50, "http://bar", "code1");
|
||||||
CompositeParam<TokenParam, QuantityParam> val = new CompositeParam<TokenParam, QuantityParam>(v0, v1);
|
CompositeParam<TokenParam, QuantityParam> val = new CompositeParam<>(v0, v1);
|
||||||
IBundleProvider result = myObservationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(param, val));
|
IBundleProvider result = myObservationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(param, val));
|
||||||
assertThat(toUnqualifiedVersionlessIdValues(result), containsInAnyOrder(id1.getValue(), id2.getValue()));
|
assertThat(toUnqualifiedVersionlessIdValues(result), containsInAnyOrder(id1.getValue(), id2.getValue()));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
TokenParam v0 = new TokenParam("http://foo", "code4");
|
TokenParam v0 = new TokenParam("http://foo", "code4");
|
||||||
QuantityParam v1 = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, 50, "http://bar", "code1");
|
QuantityParam v1 = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, 50, "http://bar", "code1");
|
||||||
CompositeParam<TokenParam, QuantityParam> val = new CompositeParam<TokenParam, QuantityParam>(v0, v1);
|
CompositeParam<TokenParam, QuantityParam> val = new CompositeParam<>(v0, v1);
|
||||||
IBundleProvider result = myObservationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(param, val));
|
IBundleProvider result = myObservationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(param, val));
|
||||||
assertThat(toUnqualifiedVersionlessIdValues(result), empty());
|
assertThat(toUnqualifiedVersionlessIdValues(result), empty());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
TokenParam v0 = new TokenParam("http://foo", "code1");
|
TokenParam v0 = new TokenParam("http://foo", "code1");
|
||||||
QuantityParam v1 = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, 50, "http://bar", "code4");
|
QuantityParam v1 = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, 50, "http://bar", "code4");
|
||||||
CompositeParam<TokenParam, QuantityParam> val = new CompositeParam<TokenParam, QuantityParam>(v0, v1);
|
CompositeParam<TokenParam, QuantityParam> val = new CompositeParam<>(v0, v1);
|
||||||
IBundleProvider result = myObservationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(param, val));
|
IBundleProvider result = myObservationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(param, val));
|
||||||
assertThat(toUnqualifiedVersionlessIdValues(result), empty());
|
assertThat(toUnqualifiedVersionlessIdValues(result), empty());
|
||||||
}
|
}
|
||||||
|
@ -1543,26 +1564,26 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSearchNumberParam() {
|
public void testSearchNumberParam() {
|
||||||
ImmunizationRecommendation e1 = new ImmunizationRecommendation();
|
RiskAssessment e1 = new RiskAssessment();
|
||||||
e1.addIdentifier().setSystem("foo").setValue("testSearchNumberParam01");
|
e1.addIdentifier().setSystem("foo").setValue("testSearchNumberParam01");
|
||||||
e1.addRecommendation().setDoseNumber(new PositiveIntType(4 * 24 * 60));
|
e1.addPrediction().setProbability(new DecimalType(4 * 24 * 60));
|
||||||
IIdType id1 = myImmunizationRecommendationDao.create(e1, mySrd).getId();
|
IIdType id1 = myRiskAssessmentDao.create(e1, mySrd).getId();
|
||||||
|
|
||||||
ImmunizationRecommendation e2 = new ImmunizationRecommendation();
|
RiskAssessment e2 = new RiskAssessment();
|
||||||
e2.addIdentifier().setSystem("foo").setValue("testSearchNumberParam02");
|
e2.addIdentifier().setSystem("foo").setValue("testSearchNumberParam02");
|
||||||
e2.addRecommendation().setDoseNumber(new PositiveIntType(4));
|
e2.addPrediction().setProbability(new DecimalType(4));
|
||||||
IIdType id2 = myImmunizationRecommendationDao.create(e2, mySrd).getId();
|
IIdType id2 = myRiskAssessmentDao.create(e2, mySrd).getId();
|
||||||
{
|
{
|
||||||
IBundleProvider found = myImmunizationRecommendationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(ImmunizationRecommendation.SP_DOSE_NUMBER, new NumberParam(">2")));
|
IBundleProvider found = myRiskAssessmentDao.search(new SearchParameterMap().setLoadSynchronous(true).add(RiskAssessment.SP_PROBABILITY, new NumberParam(">2")));
|
||||||
assertEquals(2, found.size().intValue());
|
assertEquals(2, found.size().intValue());
|
||||||
assertThat(toUnqualifiedVersionlessIds(found), containsInAnyOrder(id1.toUnqualifiedVersionless(), id2.toUnqualifiedVersionless()));
|
assertThat(toUnqualifiedVersionlessIds(found), containsInAnyOrder(id1.toUnqualifiedVersionless(), id2.toUnqualifiedVersionless()));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
IBundleProvider found = myImmunizationRecommendationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(ImmunizationRecommendation.SP_DOSE_NUMBER, new NumberParam("<1")));
|
IBundleProvider found = myRiskAssessmentDao.search(new SearchParameterMap().setLoadSynchronous(true).add(RiskAssessment.SP_PROBABILITY, new NumberParam("<1")));
|
||||||
assertEquals(0, found.size().intValue());
|
assertEquals(0, found.size().intValue());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
IBundleProvider found = myImmunizationRecommendationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(ImmunizationRecommendation.SP_DOSE_NUMBER, new NumberParam("4")));
|
IBundleProvider found = myRiskAssessmentDao.search(new SearchParameterMap().setLoadSynchronous(true).add(RiskAssessment.SP_PROBABILITY, new NumberParam("4")));
|
||||||
assertEquals(1, found.size().intValue());
|
assertEquals(1, found.size().intValue());
|
||||||
assertThat(toUnqualifiedVersionlessIds(found), containsInAnyOrder(id2.toUnqualifiedVersionless()));
|
assertThat(toUnqualifiedVersionlessIds(found), containsInAnyOrder(id2.toUnqualifiedVersionless()));
|
||||||
}
|
}
|
||||||
|
@ -2619,7 +2640,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
||||||
// Irrelevant include
|
// Irrelevant include
|
||||||
SearchParameterMap params = new SearchParameterMap();
|
SearchParameterMap params = new SearchParameterMap();
|
||||||
params.add(Patient.SP_FAMILY, new StringParam("Tester_" + methodName + "_P1"));
|
params.add(Patient.SP_FAMILY, new StringParam("Tester_" + methodName + "_P1"));
|
||||||
params.addInclude(Encounter.INCLUDE_EPISODEOFCARE);
|
params.addInclude(Encounter.INCLUDE_EPISODE_OF_CARE);
|
||||||
IBundleProvider search = myPatientDao.search(params);
|
IBundleProvider search = myPatientDao.search(params);
|
||||||
List<IBaseResource> patients = toList(search);
|
List<IBaseResource> patients = toList(search);
|
||||||
assertEquals(1, patients.size());
|
assertEquals(1, patients.size());
|
||||||
|
|
|
@ -35,6 +35,7 @@ import java.util.stream.Collectors;
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.hamcrest.Matchers.*;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
@SuppressWarnings("Duplicates")
|
||||||
public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
|
public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
public static final String URL_MY_CODE_SYSTEM = "http://example.com/my_code_system";
|
public static final String URL_MY_CODE_SYSTEM = "http://example.com/my_code_system";
|
||||||
|
@ -204,10 +205,9 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
|
||||||
validator.setValidateAgainstStandardSchematron(true);
|
validator.setValidateAgainstStandardSchematron(true);
|
||||||
ValidationResult result = validator.validateWithResult(theResult);
|
ValidationResult result = validator.validateWithResult(theResult);
|
||||||
|
|
||||||
if (!result.isSuccessful()) {
|
assertEquals(1, result.getMessages().size());
|
||||||
ourLog.info(parser.encodeResourceToString(result.toOperationOutcome()));
|
assertThat(result.getMessages().get(0).getMessage(), containsString("dom-6: A resource should have narrative for robust management"));
|
||||||
fail(parser.encodeResourceToString(result.toOperationOutcome()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1150,7 +1150,7 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
|
||||||
IIdType idIn1 = myAuditEventDao.create(aeIn1, mySrd).getId().toUnqualifiedVersionless();
|
IIdType idIn1 = myAuditEventDao.create(aeIn1, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
AuditEvent aeIn2 = new AuditEvent();
|
AuditEvent aeIn2 = new AuditEvent();
|
||||||
aeIn2.getType().setSystem("http://hl7.org/fhir/audit-event-type").setCode("rest");
|
aeIn2.getType().setSystem("http://terminology.hl7.org/CodeSystem/audit-event-type").setCode("rest");
|
||||||
IIdType idIn2 = myAuditEventDao.create(aeIn2, mySrd).getId().toUnqualifiedVersionless();
|
IIdType idIn2 = myAuditEventDao.create(aeIn2, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
AuditEvent aeOut1 = new AuditEvent();
|
AuditEvent aeOut1 = new AuditEvent();
|
||||||
|
@ -1223,7 +1223,7 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
|
||||||
// Now let's update
|
// Now let's update
|
||||||
valueSet = new ValueSet();
|
valueSet = new ValueSet();
|
||||||
valueSet.setId(vsid);
|
valueSet.setId(vsid);
|
||||||
valueSet.getCompose().addInclude().setSystem("http://hl7.org/fhir/v3/MaritalStatus").addConcept().setCode("A");
|
valueSet.getCompose().addInclude().setSystem("http://terminology.hl7.org/CodeSystem/v3-MaritalStatus").addConcept().setCode("A");
|
||||||
valueSet.setUrl(URL_MY_VALUE_SET);
|
valueSet.setUrl(URL_MY_VALUE_SET);
|
||||||
myValueSetDao.update(valueSet, mySrd).getId().toUnqualifiedVersionless();
|
myValueSetDao.update(valueSet, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
|
|
@ -745,7 +745,7 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
||||||
p.addIdentifier().setSystem("urn:system").setValue("testCreateTextIdFails");
|
p.addIdentifier().setSystem("urn:system").setValue("testCreateTextIdFails");
|
||||||
p.addName().setFamily("Hello");
|
p.addName().setFamily("Hello");
|
||||||
|
|
||||||
p.getMeta().addTag().setSystem(Constants.TAG_SUBSETTED_SYSTEM).setCode(Constants.TAG_SUBSETTED_CODE);
|
p.getMeta().addTag().setSystem(Constants.TAG_SUBSETTED_SYSTEM_DSTU3).setCode(Constants.TAG_SUBSETTED_CODE);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
myPatientDao.create(p, mySrd);
|
myPatientDao.create(p, mySrd);
|
||||||
|
|
|
@ -721,7 +721,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
Observation obs = new Observation();
|
Observation obs = new Observation();
|
||||||
obs.setSubject(new Reference(ptid));
|
obs.setSubject(new Reference(ptid));
|
||||||
obs.setContext(new Reference(encid));
|
obs.setEncounter(new Reference(encid));
|
||||||
myObservationDao.create(obs);
|
myObservationDao.create(obs);
|
||||||
|
|
||||||
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
||||||
|
|
|
@ -131,7 +131,7 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
|
||||||
input.getMeta().getProfile().add(new CanonicalType(sd.getUrl()));
|
input.getMeta().getProfile().add(new CanonicalType(sd.getUrl()));
|
||||||
|
|
||||||
input.addIdentifier().setSystem("http://acme").setValue("12345");
|
input.addIdentifier().setSystem("http://acme").setValue("12345");
|
||||||
input.getContext().setReference("http://foo.com/Encounter/9");
|
input.getEncounter().setReference("http://foo.com/Encounter/9");
|
||||||
input.setStatus(ObservationStatus.FINAL);
|
input.setStatus(ObservationStatus.FINAL);
|
||||||
input.getCode().addCoding().setSystem("http://loinc.org").setCode("12345");
|
input.getCode().addCoding().setSystem("http://loinc.org").setCode("12345");
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
|
||||||
input.getMeta().getProfile().add(new CanonicalType(profileUri));
|
input.getMeta().getProfile().add(new CanonicalType(profileUri));
|
||||||
|
|
||||||
input.addIdentifier().setSystem("http://acme").setValue("12345");
|
input.addIdentifier().setSystem("http://acme").setValue("12345");
|
||||||
input.getContext().setReference("http://foo.com/Encounter/9");
|
input.getEncounter().setReference("http://foo.com/Encounter/9");
|
||||||
input.setStatus(ObservationStatus.FINAL);
|
input.setStatus(ObservationStatus.FINAL);
|
||||||
input.getCode().addCoding().setSystem("http://loinc.org").setCode("12345");
|
input.getCode().addCoding().setSystem("http://loinc.org").setCode("12345");
|
||||||
|
|
||||||
|
|
|
@ -228,15 +228,17 @@ public class FhirResourceDaoR4ValueSetTest extends BaseJpaR4Test {
|
||||||
IPrimitiveType<String> display = null;
|
IPrimitiveType<String> display = null;
|
||||||
Coding coding = null;
|
Coding coding = null;
|
||||||
CodeableConcept codeableConcept = null;
|
CodeableConcept codeableConcept = null;
|
||||||
StringType vsIdentifier = new StringType("http://hl7.org/fhir/ValueSet/v2-0487");
|
StringType vsIdentifier = new StringType("http://hl7.org/fhir/ValueSet/yesnodontknow");
|
||||||
StringType code = new StringType("BRN");
|
StringType code = new StringType("Y");
|
||||||
StringType system = new StringType("http://hl7.org/fhir/v2/0487");
|
StringType system = new StringType("http://terminology.hl7.org/CodeSystem/v2-0136");
|
||||||
ValidateCodeResult result = myValueSetDao.validateCode(vsIdentifier, null, code, system, display, coding, codeableConcept, mySrd);
|
ValidateCodeResult result = myValueSetDao.validateCode(vsIdentifier, null, code, system, display, coding, codeableConcept, mySrd);
|
||||||
|
|
||||||
ourLog.info(result.getMessage());
|
ourLog.info(result.getMessage());
|
||||||
assertTrue(result.getMessage(), result.isResult());
|
assertTrue(result.getMessage(), result.isResult());
|
||||||
|
assertEquals("Yes", result.getDisplay());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,36 +5,42 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.dao.ISearchParamRegistry;
|
import ca.uhn.fhir.jpa.dao.ISearchParamRegistry;
|
||||||
|
import ca.uhn.fhir.jpa.dao.PathAndRef;
|
||||||
import ca.uhn.fhir.jpa.entity.BaseResourceIndexedSearchParam;
|
import ca.uhn.fhir.jpa.entity.BaseResourceIndexedSearchParam;
|
||||||
|
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamQuantity;
|
||||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamToken;
|
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamToken;
|
||||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.search.JpaRuntimeSearchParam;
|
import ca.uhn.fhir.jpa.search.JpaRuntimeSearchParam;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport;
|
import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport;
|
||||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||||
import org.hl7.fhir.r4.model.Observation;
|
import org.hl7.fhir.r4.model.*;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
public class SearchParamExtractorR4Test {
|
public class SearchParamExtractorR4Test {
|
||||||
|
|
||||||
|
private static final Logger ourLog = LoggerFactory.getLogger(SearchParamExtractorR4Test.class);
|
||||||
private static FhirContext ourCtx = FhirContext.forR4();
|
private static FhirContext ourCtx = FhirContext.forR4();
|
||||||
private static IValidationSupport ourValidationSupport;
|
private static IValidationSupport ourValidationSupport;
|
||||||
|
private ISearchParamRegistry mySearchParamRegistry;
|
||||||
|
|
||||||
@Test
|
@Before
|
||||||
public void testParamWithOrInPath() {
|
public void before() {
|
||||||
Observation obs = new Observation();
|
mySearchParamRegistry = new ISearchParamRegistry() {
|
||||||
obs.addCategory().addCoding().setSystem("SYSTEM").setCode("CODE");
|
|
||||||
|
|
||||||
ISearchParamRegistry searchParamRegistry = new ISearchParamRegistry() {
|
|
||||||
@Override
|
@Override
|
||||||
public void forceRefresh() {
|
public void forceRefresh() {
|
||||||
// nothing
|
// nothing
|
||||||
|
@ -42,7 +48,7 @@ public class SearchParamExtractorR4Test {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RuntimeSearchParam getActiveSearchParam(String theResourceName, String theParamName) {
|
public RuntimeSearchParam getActiveSearchParam(String theResourceName, String theParamName) {
|
||||||
throw new UnsupportedOperationException();
|
return getActiveSearchParams(theResourceName).get(theParamName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -81,7 +87,14 @@ public class SearchParamExtractorR4Test {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new DaoConfig(), ourCtx, ourValidationSupport, searchParamRegistry);
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParamWithOrInPath() {
|
||||||
|
Observation obs = new Observation();
|
||||||
|
obs.addCategory().addCoding().setSystem("SYSTEM").setCode("CODE");
|
||||||
|
|
||||||
|
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new DaoConfig(), ourCtx, ourValidationSupport, mySearchParamRegistry);
|
||||||
Set<BaseResourceIndexedSearchParam> tokens = extractor.extractSearchParamTokens(new ResourceTable(), obs);
|
Set<BaseResourceIndexedSearchParam> tokens = extractor.extractSearchParamTokens(new ResourceTable(), obs);
|
||||||
assertEquals(1, tokens.size());
|
assertEquals(1, tokens.size());
|
||||||
ResourceIndexedSearchParamToken token = (ResourceIndexedSearchParamToken) tokens.iterator().next();
|
ResourceIndexedSearchParamToken token = (ResourceIndexedSearchParamToken) tokens.iterator().next();
|
||||||
|
@ -90,6 +103,50 @@ public class SearchParamExtractorR4Test {
|
||||||
assertEquals("CODE", token.getValue());
|
assertEquals("CODE", token.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReferenceWithResolve() {
|
||||||
|
Encounter enc = new Encounter();
|
||||||
|
enc.addLocation().setLocation(new Reference("Location/123"));
|
||||||
|
|
||||||
|
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new DaoConfig(), ourCtx, ourValidationSupport, mySearchParamRegistry);
|
||||||
|
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam("Encounter", "location");
|
||||||
|
assertNotNull(param);
|
||||||
|
List<PathAndRef> links = extractor.extractResourceLinks(enc, param);
|
||||||
|
assertEquals(1, links.size());
|
||||||
|
assertEquals("Encounter.location.location.where(resolve() is Location)", links.get(0).getPath());
|
||||||
|
assertEquals("Location/123", ((Reference) links.get(0).getRef()).getReference());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReferenceWithResolveMulti() {
|
||||||
|
Consent consent = new Consent();
|
||||||
|
consent.setSource(new Reference().setReference("Consent/999"));
|
||||||
|
|
||||||
|
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new DaoConfig(), ourCtx, ourValidationSupport, mySearchParamRegistry);
|
||||||
|
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam("Consent", Consent.SP_SOURCE_REFERENCE);
|
||||||
|
assertNotNull(param);
|
||||||
|
List<PathAndRef> links = extractor.extractResourceLinks(consent, param);
|
||||||
|
assertEquals(1, links.size());
|
||||||
|
assertEquals("Consent.source.where(resolve() is Consent or resolve() is Contract or resolve() is QuestionnaireResponse or resolve() is DocumentReference)", links.get(0).getPath());
|
||||||
|
assertEquals("Consent/999", ((Reference) links.get(0).getRef()).getReference());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExtractComponentQuantities() {
|
||||||
|
Observation o1 = new Observation();
|
||||||
|
o1.addComponent()
|
||||||
|
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://foo").setCode("code1")))
|
||||||
|
.setValue(new Quantity().setSystem("http://bar").setCode("code1").setValue(200));
|
||||||
|
o1.addComponent()
|
||||||
|
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://foo").setCode("code2")))
|
||||||
|
.setValue(new Quantity().setSystem("http://bar").setCode("code2").setValue(200));
|
||||||
|
|
||||||
|
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new DaoConfig(), ourCtx, ourValidationSupport, mySearchParamRegistry);
|
||||||
|
Set<ResourceIndexedSearchParamQuantity> links = extractor.extractSearchParamQuantity(new ResourceTable(), o1);
|
||||||
|
ourLog.info("Links:\n {}", links.stream().map(t -> t.toString()).collect(Collectors.joining("\n ")));
|
||||||
|
assertEquals(4, links.size());
|
||||||
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
public static void afterClassClearContext() {
|
public static void afterClassClearContext() {
|
||||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
|
|
|
@ -34,7 +34,7 @@ import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.startsWith;
|
import static org.hamcrest.Matchers.startsWith;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
|
|
|
@ -39,7 +39,7 @@ import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.startsWith;
|
import static org.hamcrest.Matchers.startsWith;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
@TestPropertySource(properties = {
|
@TestPropertySource(properties = {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
|
||||||
|
@SuppressWarnings("Duplicates")
|
||||||
public class PatientEverythingR4Test extends BaseResourceProviderR4Test {
|
public class PatientEverythingR4Test extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(PatientEverythingR4Test.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(PatientEverythingR4Test.class);
|
||||||
|
|
|
@ -87,7 +87,7 @@ public class ResourceProviderR4CodeSystemTest extends BaseResourceProviderR4Test
|
||||||
.onType(CodeSystem.class)
|
.onType(CodeSystem.class)
|
||||||
.named("lookup")
|
.named("lookup")
|
||||||
.withParameter(Parameters.class, "code", new CodeType("ACSN"))
|
.withParameter(Parameters.class, "code", new CodeType("ACSN"))
|
||||||
.andParameter("system", new UriType("http://hl7.org/fhir/v2/0203"))
|
.andParameter("system", new UriType("http://terminology.hl7.org/CodeSystem/v2-0203"))
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||||
|
@ -245,7 +245,7 @@ public class ResourceProviderR4CodeSystemTest extends BaseResourceProviderR4Test
|
||||||
.onType(CodeSystem.class)
|
.onType(CodeSystem.class)
|
||||||
.named("lookup")
|
.named("lookup")
|
||||||
.withParameter(Parameters.class, "code", new CodeType("M"))
|
.withParameter(Parameters.class, "code", new CodeType("M"))
|
||||||
.andParameter("system", new UriType("http://hl7.org/fhir/v3/MaritalStatus"))
|
.andParameter("system", new UriType("http://terminology.hl7.org/CodeSystem/v3-MaritalStatus"))
|
||||||
.execute();
|
.execute();
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
|
||||||
|
|
|
@ -63,63 +63,20 @@ import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator;
|
import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator;
|
||||||
import org.hl7.fhir.r4.model.AuditEvent;
|
import org.hl7.fhir.r4.model.*;
|
||||||
import org.hl7.fhir.r4.model.BaseResource;
|
|
||||||
import org.hl7.fhir.r4.model.Basic;
|
|
||||||
import org.hl7.fhir.r4.model.Binary;
|
|
||||||
import org.hl7.fhir.r4.model.Bundle;
|
|
||||||
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
|
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
|
||||||
import org.hl7.fhir.r4.model.Bundle.BundleLinkComponent;
|
import org.hl7.fhir.r4.model.Bundle.BundleLinkComponent;
|
||||||
import org.hl7.fhir.r4.model.Bundle.BundleType;
|
import org.hl7.fhir.r4.model.Bundle.BundleType;
|
||||||
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
|
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
|
||||||
import org.hl7.fhir.r4.model.Bundle.SearchEntryMode;
|
import org.hl7.fhir.r4.model.Bundle.SearchEntryMode;
|
||||||
import org.hl7.fhir.r4.model.CarePlan;
|
|
||||||
import org.hl7.fhir.r4.model.CodeSystem;
|
|
||||||
import org.hl7.fhir.r4.model.CodeType;
|
|
||||||
import org.hl7.fhir.r4.model.Coding;
|
|
||||||
import org.hl7.fhir.r4.model.Condition;
|
|
||||||
import org.hl7.fhir.r4.model.DateTimeType;
|
|
||||||
import org.hl7.fhir.r4.model.DateType;
|
|
||||||
import org.hl7.fhir.r4.model.Device;
|
|
||||||
import org.hl7.fhir.r4.model.DocumentManifest;
|
|
||||||
import org.hl7.fhir.r4.model.DocumentReference;
|
|
||||||
import org.hl7.fhir.r4.model.Encounter;
|
|
||||||
import org.hl7.fhir.r4.model.Encounter.EncounterLocationComponent;
|
import org.hl7.fhir.r4.model.Encounter.EncounterLocationComponent;
|
||||||
import org.hl7.fhir.r4.model.Encounter.EncounterStatus;
|
import org.hl7.fhir.r4.model.Encounter.EncounterStatus;
|
||||||
import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender;
|
import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender;
|
||||||
import org.hl7.fhir.r4.model.Extension;
|
|
||||||
import org.hl7.fhir.r4.model.IdType;
|
|
||||||
import org.hl7.fhir.r4.model.ImagingStudy;
|
|
||||||
import org.hl7.fhir.r4.model.ImmunizationRecommendation;
|
|
||||||
import org.hl7.fhir.r4.model.InstantType;
|
|
||||||
import org.hl7.fhir.r4.model.IntegerType;
|
|
||||||
import org.hl7.fhir.r4.model.Location;
|
|
||||||
import org.hl7.fhir.r4.model.Medication;
|
|
||||||
import org.hl7.fhir.r4.model.MedicationAdministration;
|
|
||||||
import org.hl7.fhir.r4.model.MedicationRequest;
|
|
||||||
import org.hl7.fhir.r4.model.Meta;
|
|
||||||
import org.hl7.fhir.r4.model.Narrative.NarrativeStatus;
|
import org.hl7.fhir.r4.model.Narrative.NarrativeStatus;
|
||||||
import org.hl7.fhir.r4.model.Observation;
|
|
||||||
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
|
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
|
||||||
import org.hl7.fhir.r4.model.OperationOutcome;
|
|
||||||
import org.hl7.fhir.r4.model.Organization;
|
|
||||||
import org.hl7.fhir.r4.model.Parameters;
|
|
||||||
import org.hl7.fhir.r4.model.Patient;
|
|
||||||
import org.hl7.fhir.r4.model.Period;
|
|
||||||
import org.hl7.fhir.r4.model.Practitioner;
|
|
||||||
import org.hl7.fhir.r4.model.Quantity;
|
|
||||||
import org.hl7.fhir.r4.model.Questionnaire;
|
|
||||||
import org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemType;
|
import org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemType;
|
||||||
import org.hl7.fhir.r4.model.QuestionnaireResponse;
|
|
||||||
import org.hl7.fhir.r4.model.Reference;
|
|
||||||
import org.hl7.fhir.r4.model.ServiceRequest;
|
|
||||||
import org.hl7.fhir.r4.model.StringType;
|
|
||||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
|
||||||
import org.hl7.fhir.r4.model.Subscription;
|
|
||||||
import org.hl7.fhir.r4.model.Subscription.SubscriptionChannelType;
|
import org.hl7.fhir.r4.model.Subscription.SubscriptionChannelType;
|
||||||
import org.hl7.fhir.r4.model.Subscription.SubscriptionStatus;
|
import org.hl7.fhir.r4.model.Subscription.SubscriptionStatus;
|
||||||
import org.hl7.fhir.r4.model.UnsignedIntType;
|
|
||||||
import org.hl7.fhir.r4.model.ValueSet;
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -169,6 +126,7 @@ import ca.uhn.fhir.util.StopWatch;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
import ca.uhn.fhir.util.UrlUtil;
|
import ca.uhn.fhir.util.UrlUtil;
|
||||||
|
|
||||||
|
@SuppressWarnings("Duplicates")
|
||||||
public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderR4Test.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderR4Test.class);
|
||||||
|
@ -547,7 +505,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
IIdType optId = ourClient.create().resource(options).execute().getId();
|
IIdType optId = ourClient.create().resource(options).execute().getId();
|
||||||
|
|
||||||
Questionnaire q = new Questionnaire();
|
Questionnaire q = new Questionnaire();
|
||||||
q.addItem().setLinkId("link0").setRequired(false).setType(QuestionnaireItemType.CHOICE).setOptions((optId.getValue()));
|
q.addItem().setLinkId("link0").setRequired(false).setType(QuestionnaireItemType.CHOICE).setAnswerValueSet((optId.getValue()));
|
||||||
IIdType qId = ourClient.create().resource(q).execute().getId();
|
IIdType qId = ourClient.create().resource(q).execute().getId();
|
||||||
|
|
||||||
QuestionnaireResponse qa;
|
QuestionnaireResponse qa;
|
||||||
|
@ -747,7 +705,6 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
location.setPeriod(new Period().setStart(new Date(), TemporalPrecisionEnum.SECOND).setEnd(new Date(), TemporalPrecisionEnum.SECOND));
|
location.setPeriod(new Period().setStart(new Date(), TemporalPrecisionEnum.SECOND).setEnd(new Date(), TemporalPrecisionEnum.SECOND));
|
||||||
IIdType e1id = ourClient.create().resource(e1).execute().getId();
|
IIdType e1id = ourClient.create().resource(e1).execute().getId();
|
||||||
|
|
||||||
//@formatter:off
|
|
||||||
Bundle res = ourClient.search()
|
Bundle res = ourClient.search()
|
||||||
.forResource(Encounter.class)
|
.forResource(Encounter.class)
|
||||||
.where(Encounter.IDENTIFIER.exactly().systemAndCode("urn:foo", "testDeepChainingE1"))
|
.where(Encounter.IDENTIFIER.exactly().systemAndCode("urn:foo", "testDeepChainingE1"))
|
||||||
|
@ -755,7 +712,8 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
.include(Location.INCLUDE_PARTOF.asRecursive())
|
.include(Location.INCLUDE_PARTOF.asRecursive())
|
||||||
.returnBundle(Bundle.class)
|
.returnBundle(Bundle.class)
|
||||||
.execute();
|
.execute();
|
||||||
//@formatter:on
|
|
||||||
|
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(res));
|
||||||
|
|
||||||
assertEquals(3, res.getEntry().size());
|
assertEquals(3, res.getEntry().size());
|
||||||
assertEquals(1, genResourcesOfType(res, Encounter.class).size());
|
assertEquals(1, genResourcesOfType(res, Encounter.class).size());
|
||||||
|
@ -763,6 +721,45 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReferenceOfWrongType() {
|
||||||
|
Group l2 = new Group();
|
||||||
|
l2.setActive(true);
|
||||||
|
IIdType l2id = ourClient.create().resource(l2).execute().getId();
|
||||||
|
|
||||||
|
Encounter e1 = new Encounter();
|
||||||
|
e1.getStatusElement().setValue(EncounterStatus.INPROGRESS);
|
||||||
|
e1.getSubject().setReference(l2id.toUnqualifiedVersionless().getValue());
|
||||||
|
IIdType e1id = ourClient.create().resource(e1).execute().getId();
|
||||||
|
|
||||||
|
// Wrong type
|
||||||
|
Bundle res = ourClient.search()
|
||||||
|
.forResource(Encounter.class)
|
||||||
|
.include(Encounter.INCLUDE_PATIENT.asRecursive())
|
||||||
|
.returnBundle(Bundle.class)
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(res));
|
||||||
|
|
||||||
|
assertEquals(1, res.getEntry().size());
|
||||||
|
assertEquals(1, genResourcesOfType(res, Encounter.class).size());
|
||||||
|
assertEquals(e1id.toUnqualifiedVersionless(), genResourcesOfType(res, Encounter.class).get(0).getIdElement().toUnqualifiedVersionless());
|
||||||
|
|
||||||
|
// Right type
|
||||||
|
res = ourClient.search()
|
||||||
|
.forResource(Encounter.class)
|
||||||
|
.include(Encounter.INCLUDE_SUBJECT.asRecursive())
|
||||||
|
.returnBundle(Bundle.class)
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(res));
|
||||||
|
|
||||||
|
assertEquals(2, res.getEntry().size());
|
||||||
|
assertEquals(1, genResourcesOfType(res, Encounter.class).size());
|
||||||
|
assertEquals(1, genResourcesOfType(res, Group.class).size());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteConditionalMultiple() {
|
public void testDeleteConditionalMultiple() {
|
||||||
String methodName = "testDeleteConditionalMultiple";
|
String methodName = "testDeleteConditionalMultiple";
|
||||||
|
@ -830,16 +827,13 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
String methodName = "testDeleteConditionalNoMatches";
|
String methodName = "testDeleteConditionalNoMatches";
|
||||||
|
|
||||||
HttpDelete delete = new HttpDelete(ourServerBase + "/Patient?identifier=" + methodName);
|
HttpDelete delete = new HttpDelete(ourServerBase + "/Patient?identifier=" + methodName);
|
||||||
CloseableHttpResponse resp = ourHttpClient.execute(delete);
|
try (CloseableHttpResponse resp = ourHttpClient.execute(delete)) {
|
||||||
try {
|
|
||||||
ourLog.info(resp.toString());
|
ourLog.info(resp.toString());
|
||||||
String response = IOUtils.toString(resp.getEntity().getContent(), StandardCharsets.UTF_8);
|
String response = IOUtils.toString(resp.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
ourLog.info(response);
|
ourLog.info(response);
|
||||||
assertEquals(200, resp.getStatusLine().getStatusCode());
|
assertEquals(200, resp.getStatusLine().getStatusCode());
|
||||||
assertThat(response, containsString(
|
assertThat(response, containsString(
|
||||||
"<issue><severity value=\"warning\"/><code value=\"not-found\"/><diagnostics value=\"Unable to find resource matching URL "Patient?identifier=testDeleteConditionalNoMatches". Deletion failed.\"/></issue>"));
|
"<issue><severity value=\"warning\"/><code value=\"not-found\"/><diagnostics value=\"Unable to find resource matching URL "Patient?identifier=testDeleteConditionalNoMatches". Deletion failed.\"/></issue>"));
|
||||||
} finally {
|
|
||||||
IOUtils.closeQuietly(resp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -847,14 +841,11 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteInvalidReference() throws IOException {
|
public void testDeleteInvalidReference() throws IOException {
|
||||||
HttpDelete delete = new HttpDelete(ourServerBase + "/Patient");
|
HttpDelete delete = new HttpDelete(ourServerBase + "/Patient");
|
||||||
CloseableHttpResponse response = ourHttpClient.execute(delete);
|
try (CloseableHttpResponse response = ourHttpClient.execute(delete)) {
|
||||||
try {
|
|
||||||
String responseString = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
String responseString = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
ourLog.info(responseString);
|
ourLog.info(responseString);
|
||||||
assertEquals(400, response.getStatusLine().getStatusCode());
|
assertEquals(400, response.getStatusLine().getStatusCode());
|
||||||
assertThat(responseString, containsString("Can not perform delete, no ID provided"));
|
assertThat(responseString, containsString("Can not perform delete, no ID provided"));
|
||||||
} finally {
|
|
||||||
response.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1096,7 +1087,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
IIdType orgId2 = ourClient.create().resource(org2).execute().getId().toUnqualifiedVersionless();
|
IIdType orgId2 = ourClient.create().resource(org2).execute().getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
Device dev = new Device();
|
Device dev = new Device();
|
||||||
dev.setModel(methodName);
|
dev.setManufacturer(methodName);
|
||||||
dev.getOwner().setReferenceElement(orgId2);
|
dev.getOwner().setReferenceElement(orgId2);
|
||||||
IIdType devId = ourClient.create().resource(dev).execute().getId().toUnqualifiedVersionless();
|
IIdType devId = ourClient.create().resource(dev).execute().getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
@ -1122,7 +1113,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
Observation obs = new Observation();
|
Observation obs = new Observation();
|
||||||
obs.getSubject().setReferenceElement(patientId);
|
obs.getSubject().setReferenceElement(patientId);
|
||||||
obs.getDevice().setReferenceElement(devId);
|
obs.getDevice().setReferenceElement(devId);
|
||||||
obs.getContext().setReferenceElement(encId);
|
obs.getEncounter().setReferenceElement(encId);
|
||||||
IIdType obsId = ourClient.create().resource(obs).execute().getId().toUnqualifiedVersionless();
|
IIdType obsId = ourClient.create().resource(obs).execute().getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
ourLog.info("IDs: EncU:" + encUId.getIdPart() + " Enc:" + encId.getIdPart() + " " + patientId.toUnqualifiedVersionless());
|
ourLog.info("IDs: EncU:" + encUId.getIdPart() + " Enc:" + encId.getIdPart() + " " + patientId.toUnqualifiedVersionless());
|
||||||
|
@ -1160,7 +1151,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
IIdType orgId2 = ourClient.create().resource(org2).execute().getId().toUnqualifiedVersionless();
|
IIdType orgId2 = ourClient.create().resource(org2).execute().getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
Device dev = new Device();
|
Device dev = new Device();
|
||||||
dev.setModel(methodName);
|
dev.setManufacturer(methodName);
|
||||||
dev.getOwner().setReferenceElement(orgId2);
|
dev.getOwner().setReferenceElement(orgId2);
|
||||||
IIdType devId = ourClient.create().resource(dev).execute().getId().toUnqualifiedVersionless();
|
IIdType devId = ourClient.create().resource(dev).execute().getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
@ -1185,7 +1176,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
Observation obs = new Observation();
|
Observation obs = new Observation();
|
||||||
obs.getSubject().setReferenceElement(patientId);
|
obs.getSubject().setReferenceElement(patientId);
|
||||||
obs.getDevice().setReferenceElement(devId);
|
obs.getDevice().setReferenceElement(devId);
|
||||||
obs.getContext().setReferenceElement(encId);
|
obs.getEncounter().setReferenceElement(encId);
|
||||||
IIdType obsId = ourClient.create().resource(obs).execute().getId().toUnqualifiedVersionless();
|
IIdType obsId = ourClient.create().resource(obs).execute().getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
Parameters output = ourClient.operation().onType(Encounter.class).named("everything").withNoParameters(Parameters.class).execute();
|
Parameters output = ourClient.operation().onType(Encounter.class).named("everything").withNoParameters(Parameters.class).execute();
|
||||||
|
@ -1402,7 +1393,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
IIdType orgId2 = ourClient.create().resource(org2).execute().getId().toUnqualifiedVersionless();
|
IIdType orgId2 = ourClient.create().resource(org2).execute().getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
Device dev = new Device();
|
Device dev = new Device();
|
||||||
dev.setModel(methodName);
|
dev.setManufacturer(methodName);
|
||||||
dev.getOwner().setReferenceElement(orgId2);
|
dev.getOwner().setReferenceElement(orgId2);
|
||||||
IIdType devId = ourClient.create().resource(dev).execute().getId().toUnqualifiedVersionless();
|
IIdType devId = ourClient.create().resource(dev).execute().getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
@ -1562,6 +1553,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
* Per message from David Hay on Skype
|
* Per message from David Hay on Skype
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore
|
||||||
public void testEverythingWithLargeSet() throws Exception {
|
public void testEverythingWithLargeSet() throws Exception {
|
||||||
|
|
||||||
String inputString = IOUtils.toString(getClass().getResourceAsStream("/david_big_bundle.json"), StandardCharsets.UTF_8);
|
String inputString = IOUtils.toString(getClass().getResourceAsStream("/david_big_bundle.json"), StandardCharsets.UTF_8);
|
||||||
|
@ -1975,6 +1967,8 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
assertEquals(id.withVersion("1").getValue(), history.getEntry().get(2).getResource().getId());
|
assertEquals(id.withVersion("1").getValue(), history.getEntry().get(2).getResource().getId());
|
||||||
assertEquals(1, ((Patient) history.getEntry().get(2).getResource()).getName().size());
|
assertEquals(1, ((Patient) history.getEntry().get(2).getResource()).getName().size());
|
||||||
|
|
||||||
|
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(history));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
myBundleDao.validate(history, null, null, null, null, null, mySrd);
|
myBundleDao.validate(history, null, null, null, null, null, mySrd);
|
||||||
} catch (PreconditionFailedException e) {
|
} catch (PreconditionFailedException e) {
|
||||||
|
@ -2537,7 +2531,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
assertEquals("1", patientId.getVersionIdPart());
|
assertEquals("1", patientId.getVersionIdPart());
|
||||||
|
|
||||||
AuditEvent ae = new org.hl7.fhir.r4.model.AuditEvent();
|
AuditEvent ae = new org.hl7.fhir.r4.model.AuditEvent();
|
||||||
ae.addEntity().getReference().setReference(patientId.toUnqualified().getValue());
|
ae.addEntity().getWhat().setReference(patientId.toUnqualified().getValue());
|
||||||
IIdType aeId = ourClient.create().resource(ae).execute().getId();
|
IIdType aeId = ourClient.create().resource(ae).execute().getId();
|
||||||
assertEquals("1", aeId.getVersionIdPart());
|
assertEquals("1", aeId.getVersionIdPart());
|
||||||
|
|
||||||
|
@ -2546,8 +2540,8 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
assertFalse(patient.getManagingOrganization().getReferenceElement().hasVersionIdPart());
|
assertFalse(patient.getManagingOrganization().getReferenceElement().hasVersionIdPart());
|
||||||
|
|
||||||
ae = ourClient.read().resource(AuditEvent.class).withId(aeId).execute();
|
ae = ourClient.read().resource(AuditEvent.class).withId(aeId).execute();
|
||||||
assertTrue(ae.getEntityFirstRep().getReference().getReferenceElement().hasIdPart());
|
assertTrue(ae.getEntityFirstRep().getWhat().getReferenceElement().hasIdPart());
|
||||||
assertTrue(ae.getEntityFirstRep().getReference().getReferenceElement().hasVersionIdPart());
|
assertTrue(ae.getEntityFirstRep().getWhat().getReferenceElement().hasVersionIdPart());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3740,8 +3734,8 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
try {
|
try {
|
||||||
ourClient
|
ourClient
|
||||||
.search()
|
.search()
|
||||||
.forResource(ImmunizationRecommendation.class)
|
.forResource(Sequence.class)
|
||||||
.where(ImmunizationRecommendation.DOSE_NUMBER.withPrefix(ParamPrefixEnum.ENDS_BEFORE).number(100))
|
.where(Sequence.END.withPrefix(ParamPrefixEnum.ENDS_BEFORE).number(100))
|
||||||
.prettyPrint()
|
.prettyPrint()
|
||||||
.returnBundle(Bundle.class)
|
.returnBundle(Bundle.class)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
|
@ -114,7 +114,7 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
|
||||||
myLocalVs = new ValueSet();
|
myLocalVs = new ValueSet();
|
||||||
myLocalVs.setUrl(URL_MY_VALUE_SET);
|
myLocalVs.setUrl(URL_MY_VALUE_SET);
|
||||||
ConceptSetComponent include = myLocalVs.getCompose().addInclude();
|
ConceptSetComponent include = myLocalVs.getCompose().addInclude();
|
||||||
include.setSystem("http://hl7.org/fhir/v3/MaritalStatus");
|
include.setSystem("http://terminology.hl7.org/CodeSystem/v3-MaritalStatus");
|
||||||
myLocalValueSetId = myValueSetDao.create(myLocalVs, mySrd).getId().toUnqualifiedVersionless();
|
myLocalValueSetId = myValueSetDao.create(myLocalVs, mySrd).getId().toUnqualifiedVersionless();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -505,9 +505,9 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
|
||||||
.operation()
|
.operation()
|
||||||
.onType(ValueSet.class)
|
.onType(ValueSet.class)
|
||||||
.named("validate-code")
|
.named("validate-code")
|
||||||
.withParameter(Parameters.class, "code", new StringType("BRN"))
|
.withParameter(Parameters.class, "code", new StringType("Y"))
|
||||||
.andParameter("url", new StringType("http://hl7.org/fhir/ValueSet/v2-0487"))
|
.andParameter("url", new StringType("http://hl7.org/fhir/ValueSet/yesnodontknow"))
|
||||||
.andParameter("system", new StringType("http://hl7.org/fhir/v2/0487"))
|
.andParameter("system", new StringType("http://terminology.hl7.org/CodeSystem/v2-0136"))
|
||||||
.useHttpGet()
|
.useHttpGet()
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
|
@ -521,7 +521,7 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
|
||||||
assertThat(((StringType) respParam.getParameter().get(1).getValue()).getValue(), containsStringIgnoringCase("succeeded"));
|
assertThat(((StringType) respParam.getParameter().get(1).getValue()).getValue(), containsStringIgnoringCase("succeeded"));
|
||||||
|
|
||||||
assertEquals("display", respParam.getParameter().get(2).getName());
|
assertEquals("display", respParam.getParameter().get(2).getName());
|
||||||
assertEquals("Burn", ((StringType) respParam.getParameter().get(2).getValue()).getValue());
|
assertEquals("Yes", ((StringType) respParam.getParameter().get(2).getValue()).getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
|
|
|
@ -101,7 +101,7 @@ public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Tes
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUploadMissingPackage() throws Exception {
|
public void testUploadMissingPackage() {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
try {
|
try {
|
||||||
ourClient
|
ourClient
|
||||||
|
|
|
@ -42,10 +42,10 @@ import javax.persistence.EntityManager;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Matchers.anyBoolean;
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Matchers.same;
|
import static org.mockito.ArgumentMatchers.same;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
|
|
|
@ -95,9 +95,9 @@ public class RestHookWithEventDefinitionR4Test extends BaseResourceProviderR4Tes
|
||||||
.setPurpose("Monitor all admissions to Emergency")
|
.setPurpose("Monitor all admissions to Emergency")
|
||||||
.setTrigger(new TriggerDefinition()
|
.setTrigger(new TriggerDefinition()
|
||||||
.setType(TriggerDefinition.TriggerType.DATAADDED)
|
.setType(TriggerDefinition.TriggerType.DATAADDED)
|
||||||
.setCondition(new TriggerDefinition.TriggerDefinitionConditionComponent()
|
.setCondition(new Expression()
|
||||||
.setDescription("Encounter Location = emergency (active/completed encounters, current or previous)")
|
.setDescription("Encounter Location = emergency (active/completed encounters, current or previous)")
|
||||||
.setLanguage(TriggerDefinition.ExpressionLanguage.TEXT_FHIRPATH)
|
.setLanguage(Expression.ExpressionLanguage.TEXT_FHIRPATH)
|
||||||
.setExpression("(this | %previous).location.where(location = 'Location/emergency' and status in {'active', 'completed'}).exists()")
|
.setExpression("(this | %previous).location.where(location = 'Location/emergency' and status in {'active', 'completed'}).exists()")
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -2043,8 +2043,6 @@
|
||||||
<profile value="http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition"/>
|
<profile value="http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition"/>
|
||||||
<!--CDA templateId: urn:hl7ii:2.16.840.1.113883.10.20.22.4.4:2015-08-01-->
|
<!--CDA templateId: urn:hl7ii:2.16.840.1.113883.10.20.22.4.4:2015-08-01-->
|
||||||
</meta>
|
</meta>
|
||||||
<clinicalStatus value="active"/>
|
|
||||||
<verificationStatus value="confirmed"/>
|
|
||||||
<category>
|
<category>
|
||||||
<coding>
|
<coding>
|
||||||
<system value="http://snomed.info/sct"/>
|
<system value="http://snomed.info/sct"/>
|
||||||
|
@ -2116,8 +2114,6 @@
|
||||||
<profile value="http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition"/>
|
<profile value="http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition"/>
|
||||||
<!--CDA templateId: urn:hl7ii:2.16.840.1.113883.10.20.22.4.4:2015-08-01-->
|
<!--CDA templateId: urn:hl7ii:2.16.840.1.113883.10.20.22.4.4:2015-08-01-->
|
||||||
</meta>
|
</meta>
|
||||||
<clinicalStatus value="active"/>
|
|
||||||
<verificationStatus value="confirmed"/>
|
|
||||||
<category>
|
<category>
|
||||||
<coding>
|
<coding>
|
||||||
<system value="http://hl7.org/fhir/v3/ActCode"/>
|
<system value="http://hl7.org/fhir/v3/ActCode"/>
|
||||||
|
|
|
@ -348,17 +348,17 @@
|
||||||
<item>
|
<item>
|
||||||
<linkId value="1.1"/>
|
<linkId value="1.1"/>
|
||||||
<type value="choice"/>
|
<type value="choice"/>
|
||||||
<options value="#verbal"/>
|
<answerValueSet value="#verbal"/>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<linkId value="1.2"/>
|
<linkId value="1.2"/>
|
||||||
<type value="choice"/>
|
<type value="choice"/>
|
||||||
<options value="#motor"/>
|
<answerValueSet value="#motor"/>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<linkId value="1.3"/>
|
<linkId value="1.3"/>
|
||||||
<type value="choice"/>
|
<type value="choice"/>
|
||||||
<options value="#eye"/>
|
<answerValueSet value="#eye"/>
|
||||||
</item>
|
</item>
|
||||||
</Questionnaire>
|
</Questionnaire>
|
||||||
</resource>
|
</resource>
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
},
|
},
|
||||||
"id": "cf-1505178568463",
|
"id": "cf-1505178568463",
|
||||||
"subject": {"reference": "Patient/2344"},
|
"subject": {"reference": "Patient/2344"},
|
||||||
"clinicalStatus": "active",
|
|
||||||
"code": {"coding": [{
|
"code": {"coding": [{
|
||||||
"system": "http://snomed.info/sct",
|
"system": "http://snomed.info/sct",
|
||||||
"code": "170631002",
|
"code": "170631002",
|
||||||
|
|
|
@ -69,7 +69,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"created" : "2005-12-24T09:35:00+11:00",
|
|
||||||
"status" : "current",
|
"status" : "current",
|
||||||
"description" : "Physical",
|
"description" : "Physical",
|
||||||
"context" : {
|
"context" : {
|
||||||
|
|
|
@ -261,7 +261,7 @@
|
||||||
"subject": {
|
"subject": {
|
||||||
"reference": "urn:uuid:09a8d22c-1e23-4e5f-b3bf-505772f123d1"
|
"reference": "urn:uuid:09a8d22c-1e23-4e5f-b3bf-505772f123d1"
|
||||||
},
|
},
|
||||||
"context": {
|
"encounter": {
|
||||||
"reference": "urn:uuid:29e3a213-0df4-41e0-88f8-e3be83277022"
|
"reference": "urn:uuid:29e3a213-0df4-41e0-88f8-e3be83277022"
|
||||||
},
|
},
|
||||||
"effectiveDateTime": "2011-12-01T09:49:00-05:00",
|
"effectiveDateTime": "2011-12-01T09:49:00-05:00",
|
||||||
|
@ -289,7 +289,7 @@
|
||||||
"subject": {
|
"subject": {
|
||||||
"reference": "urn:uuid:09a8d22c-1e23-4e5f-b3bf-505772f123d1"
|
"reference": "urn:uuid:09a8d22c-1e23-4e5f-b3bf-505772f123d1"
|
||||||
},
|
},
|
||||||
"context": {
|
"encounter": {
|
||||||
"reference": "urn:uuid:29e3a213-0df4-41e0-88f8-e3be83277022"
|
"reference": "urn:uuid:29e3a213-0df4-41e0-88f8-e3be83277022"
|
||||||
},
|
},
|
||||||
"effectiveDateTime": "2011-12-01T09:49:00-05:00",
|
"effectiveDateTime": "2011-12-01T09:49:00-05:00",
|
||||||
|
@ -317,7 +317,7 @@
|
||||||
"subject": {
|
"subject": {
|
||||||
"reference": "urn:uuid:09a8d22c-1e23-4e5f-b3bf-505772f123d1"
|
"reference": "urn:uuid:09a8d22c-1e23-4e5f-b3bf-505772f123d1"
|
||||||
},
|
},
|
||||||
"context": {
|
"encounter": {
|
||||||
"reference": "urn:uuid:29e3a213-0df4-41e0-88f8-e3be83277022"
|
"reference": "urn:uuid:29e3a213-0df4-41e0-88f8-e3be83277022"
|
||||||
},
|
},
|
||||||
"effectiveDateTime": "2011-12-01T09:49:00-05:00",
|
"effectiveDateTime": "2011-12-01T09:49:00-05:00",
|
||||||
|
@ -345,7 +345,7 @@
|
||||||
"subject": {
|
"subject": {
|
||||||
"reference": "urn:uuid:09a8d22c-1e23-4e5f-b3bf-505772f123d1"
|
"reference": "urn:uuid:09a8d22c-1e23-4e5f-b3bf-505772f123d1"
|
||||||
},
|
},
|
||||||
"context": {
|
"encounter": {
|
||||||
"reference": "urn:uuid:29e3a213-0df4-41e0-88f8-e3be83277022"
|
"reference": "urn:uuid:29e3a213-0df4-41e0-88f8-e3be83277022"
|
||||||
},
|
},
|
||||||
"effectiveDateTime": "2011-12-01T10:57:00-05:00",
|
"effectiveDateTime": "2011-12-01T10:57:00-05:00",
|
||||||
|
|
|
@ -131,7 +131,7 @@
|
||||||
"binding": {
|
"binding": {
|
||||||
"strength": "example",
|
"strength": "example",
|
||||||
"description": "Codes for identifying types of resources not yet defined by FHIR",
|
"description": "Codes for identifying types of resources not yet defined by FHIR",
|
||||||
"valueSetCanonical": "http://hl7.org/fhir/ValueSet/basic-resource-type"
|
"valueSet": "http://hl7.org/fhir/ValueSet/basic-resource-type"
|
||||||
},
|
},
|
||||||
"mapping": [
|
"mapping": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.migrate;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.migrate.taskdef.BaseTableColumnTypeTask;
|
import ca.uhn.fhir.jpa.migrate.taskdef.BaseTableColumnTypeTask;
|
||||||
|
import ca.uhn.fhir.jpa.migrate.taskdef.BaseTableTask;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -126,6 +127,11 @@ public class JdbcUtils {
|
||||||
return BaseTableColumnTypeTask.ColumnTypeEnum.STRING.getDescriptor(length);
|
return BaseTableColumnTypeTask.ColumnTypeEnum.STRING.getDescriptor(length);
|
||||||
case Types.BIGINT:
|
case Types.BIGINT:
|
||||||
return BaseTableColumnTypeTask.ColumnTypeEnum.LONG.getDescriptor(null);
|
return BaseTableColumnTypeTask.ColumnTypeEnum.LONG.getDescriptor(null);
|
||||||
|
case Types.INTEGER:
|
||||||
|
return BaseTableColumnTypeTask.ColumnTypeEnum.INT.getDescriptor(null);
|
||||||
|
case Types.TIMESTAMP:
|
||||||
|
case Types.TIMESTAMP_WITH_TIMEZONE:
|
||||||
|
return BaseTableColumnTypeTask.ColumnTypeEnum.DATE_TIMESTAMP.getDescriptor(null);
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Don't know how to handle datatype: " + dataType);
|
throw new IllegalArgumentException("Don't know how to handle datatype: " + dataType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,13 @@ public abstract class BaseTableColumnTypeTask<T extends BaseTableTask> extends B
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
BaseTableColumnTypeTask() {
|
BaseTableColumnTypeTask() {
|
||||||
|
setColumnType(ColumnTypeEnum.INT, DriverTypeEnum.DERBY_EMBEDDED, "integer");
|
||||||
|
setColumnType(ColumnTypeEnum.INT, DriverTypeEnum.MARIADB_10_1, "integer");
|
||||||
|
setColumnType(ColumnTypeEnum.INT, DriverTypeEnum.MYSQL_5_7, "integer");
|
||||||
|
setColumnType(ColumnTypeEnum.INT, DriverTypeEnum.MSSQL_2012, "int");
|
||||||
|
setColumnType(ColumnTypeEnum.INT, DriverTypeEnum.ORACLE_12C, "number(10,0)");
|
||||||
|
setColumnType(ColumnTypeEnum.INT, DriverTypeEnum.POSTGRES_9_4, "int4");
|
||||||
|
|
||||||
setColumnType(ColumnTypeEnum.LONG, DriverTypeEnum.DERBY_EMBEDDED, "bigint");
|
setColumnType(ColumnTypeEnum.LONG, DriverTypeEnum.DERBY_EMBEDDED, "bigint");
|
||||||
setColumnType(ColumnTypeEnum.LONG, DriverTypeEnum.MARIADB_10_1, "bigint");
|
setColumnType(ColumnTypeEnum.LONG, DriverTypeEnum.MARIADB_10_1, "bigint");
|
||||||
setColumnType(ColumnTypeEnum.LONG, DriverTypeEnum.MYSQL_5_7, "bigint");
|
setColumnType(ColumnTypeEnum.LONG, DriverTypeEnum.MYSQL_5_7, "bigint");
|
||||||
|
@ -147,8 +154,16 @@ public abstract class BaseTableColumnTypeTask<T extends BaseTableTask> extends B
|
||||||
Assert.isTrue(theColumnLength == null, "Must not supply a column length");
|
Assert.isTrue(theColumnLength == null, "Must not supply a column length");
|
||||||
return "timestamp";
|
return "timestamp";
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
INT {
|
||||||
|
@Override
|
||||||
|
public String getDescriptor(Long theColumnLength) {
|
||||||
|
Assert.isTrue(theColumnLength == null, "Must not supply a column length");
|
||||||
|
return "int";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
public abstract String getDescriptor(Long theColumnLength);
|
public abstract String getDescriptor(Long theColumnLength);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,22 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
public HapiFhirJpaMigrationTasks() {
|
public HapiFhirJpaMigrationTasks() {
|
||||||
|
init340();
|
||||||
init350();
|
init350();
|
||||||
|
init360();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init360() {
|
||||||
|
Builder version = forVersion(VersionEnum.V3_6_0);
|
||||||
|
|
||||||
|
// Resource Link
|
||||||
|
Builder.BuilderWithTableName resourceLink = version.onTable("HFJ_RES_LINK");
|
||||||
|
version.startSectionWithMessage("Starting work on table: " + resourceLink.getTableName());
|
||||||
|
resourceLink
|
||||||
|
.modifyColumn("SRC_PATH")
|
||||||
|
.nonNullable()
|
||||||
|
.withType(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, ResourceLink.SRC_PATH_LENGTH);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init350() {
|
private void init350() {
|
||||||
|
@ -425,5 +440,39 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
||||||
.addSql(DriverTypeEnum.MSSQL_2012, "alter table TRM_CONCEPT_MAP_GRP_ELM_TGT add constraint FK_TCMGETARGET_ELEMENT foreign key (CONCEPT_MAP_GRP_ELM_PID) references TRM_CONCEPT_MAP_GRP_ELEMENT");
|
.addSql(DriverTypeEnum.MSSQL_2012, "alter table TRM_CONCEPT_MAP_GRP_ELM_TGT add constraint FK_TCMGETARGET_ELEMENT foreign key (CONCEPT_MAP_GRP_ELM_PID) references TRM_CONCEPT_MAP_GRP_ELEMENT");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void init340() {
|
||||||
|
Builder version = forVersion(VersionEnum.V3_4_0);
|
||||||
|
|
||||||
|
// CodeSystem Version
|
||||||
|
Builder.BuilderWithTableName resourceLink = version.onTable("TRM_CODESYSTEM_VER");
|
||||||
|
version.startSectionWithMessage("Starting work on table: " + resourceLink.getTableName());
|
||||||
|
resourceLink
|
||||||
|
.dropIndex("IDX_CSV_RESOURCEPID_AND_VER");
|
||||||
|
resourceLink
|
||||||
|
.dropColumn("RES_VERSION_ID");
|
||||||
|
resourceLink
|
||||||
|
.addColumn("CS_VERSION_ID")
|
||||||
|
.nullable()
|
||||||
|
.type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 255);
|
||||||
|
resourceLink
|
||||||
|
.addColumn("CODESYSTEM_PID")
|
||||||
|
.nullable()
|
||||||
|
.type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
|
||||||
|
resourceLink
|
||||||
|
.addForeignKey("FK_CODESYSVER_CS_ID")
|
||||||
|
.toColumn("CODESYSTEM_PID")
|
||||||
|
.references("TRM_CODESYSTEM", "PID");
|
||||||
|
|
||||||
|
// Concept
|
||||||
|
Builder.BuilderWithTableName concept = version.onTable("TRM_CONCEPT");
|
||||||
|
version.startSectionWithMessage("Starting work on table: " + concept.getTableName());
|
||||||
|
concept
|
||||||
|
.addColumn("CODE_SEQUENCE")
|
||||||
|
.nullable()
|
||||||
|
.type(BaseTableColumnTypeTask.ColumnTypeEnum.INT);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import org.junit.Test;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
public class AddColumnTest extends BaseTest {
|
public class AddColumnTest extends BaseTest {
|
||||||
|
@ -26,6 +27,23 @@ public class AddColumnTest extends BaseTest {
|
||||||
assertThat(JdbcUtils.getColumnNames(getConnectionProperties(), "SOMETABLE"), containsInAnyOrder("PID", "TEXTCOL", "NEWCOL"));
|
assertThat(JdbcUtils.getColumnNames(getConnectionProperties(), "SOMETABLE"), containsInAnyOrder("PID", "TEXTCOL", "NEWCOL"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddColumnInt() throws SQLException {
|
||||||
|
executeSql("create table SOMETABLE (PID bigint not null, TEXTCOL varchar(255))");
|
||||||
|
|
||||||
|
AddColumnTask task = new AddColumnTask();
|
||||||
|
task.setTableName("SOMETABLE");
|
||||||
|
task.setColumnName("newcolint");
|
||||||
|
task.setColumnType(AddColumnTask.ColumnTypeEnum.INT);
|
||||||
|
task.setNullable(true);
|
||||||
|
getMigrator().addTask(task);
|
||||||
|
|
||||||
|
getMigrator().migrate();
|
||||||
|
|
||||||
|
String type = JdbcUtils.getColumnType(getConnectionProperties(), "SOMETABLE", "newcolint");
|
||||||
|
assertEquals(BaseTableColumnTypeTask.ColumnTypeEnum.INT.getDescriptor(null), type);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testColumnAlreadyExists() throws SQLException {
|
public void testColumnAlreadyExists() throws SQLException {
|
||||||
executeSql("create table SOMETABLE (PID bigint not null, TEXTCOL varchar(255), newcol bigint)");
|
executeSql("create table SOMETABLE (PID bigint not null, TEXTCOL varchar(255), newcol bigint)");
|
||||||
|
|
|
@ -59,6 +59,8 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
|
||||||
retVal.setCountSearchResultsUpTo(TestR4Config.COUNT_SEARCH_RESULTS_UP_TO);
|
retVal.setCountSearchResultsUpTo(TestR4Config.COUNT_SEARCH_RESULTS_UP_TO);
|
||||||
retVal.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
|
retVal.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
|
||||||
retVal.setFetchSizeDefaultMaximum(10000);
|
retVal.setFetchSizeDefaultMaximum(10000);
|
||||||
|
retVal.setReindexThreadCount(1);
|
||||||
|
retVal.setExpungeEnabled(true);
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ public class TestR4Config extends BaseJavaConfigR4 {
|
||||||
retVal.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
|
retVal.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
|
||||||
retVal.setCountSearchResultsUpTo(TestR4Config.COUNT_SEARCH_RESULTS_UP_TO);
|
retVal.setCountSearchResultsUpTo(TestR4Config.COUNT_SEARCH_RESULTS_UP_TO);
|
||||||
retVal.setFetchSizeDefaultMaximum(10000);
|
retVal.setFetchSizeDefaultMaximum(10000);
|
||||||
|
retVal.setExpungeEnabled(true);
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhirtest.interceptor;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.provider.BaseJpaSystemProvider;
|
import ca.uhn.fhir.jpa.provider.BaseJpaSystemProvider;
|
||||||
import ca.uhn.fhir.jpa.provider.BaseTerminologyUploaderProvider;
|
import ca.uhn.fhir.jpa.provider.BaseTerminologyUploaderProvider;
|
||||||
|
import ca.uhn.fhir.jpa.util.JpaConstants;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
|
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor;
|
||||||
|
@ -35,6 +36,9 @@ public class PublicSecurityInterceptor extends AuthorizationInterceptor {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.deny().operation().named(BaseJpaSystemProvider.MARK_ALL_RESOURCES_FOR_REINDEXING).onServer().andThen()
|
.deny().operation().named(BaseJpaSystemProvider.MARK_ALL_RESOURCES_FOR_REINDEXING).onServer().andThen()
|
||||||
.deny().operation().named(BaseTerminologyUploaderProvider.UPLOAD_EXTERNAL_CODE_SYSTEM).onServer().andThen()
|
.deny().operation().named(BaseTerminologyUploaderProvider.UPLOAD_EXTERNAL_CODE_SYSTEM).onServer().andThen()
|
||||||
|
.deny().operation().named(JpaConstants.OPERATION_EXPUNGE).onServer().andThen()
|
||||||
|
.deny().operation().named(JpaConstants.OPERATION_EXPUNGE).onAnyType().andThen()
|
||||||
|
.deny().operation().named(JpaConstants.OPERATION_EXPUNGE).onAnyInstance().andThen()
|
||||||
.allowAll()
|
.allowAll()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
|
@ -644,9 +644,11 @@ public class RestfulServerUtils {
|
||||||
|
|
||||||
if (theServer.getETagSupport() == ETagSupportEnum.ENABLED) {
|
if (theServer.getETagSupport() == ETagSupportEnum.ENABLED) {
|
||||||
if (fullId != null && fullId.hasVersionIdPart()) {
|
if (fullId != null && fullId.hasVersionIdPart()) {
|
||||||
response.addHeader(Constants.HEADER_ETAG, "W/\"" + fullId.getVersionIdPart() + '"');
|
String versionIdPart = fullId.getVersionIdPart();
|
||||||
|
response.addHeader(Constants.HEADER_ETAG, createEtag(versionIdPart));
|
||||||
} else if (theResource != null && theResource.getMeta() != null && isNotBlank(theResource.getMeta().getVersionId())) {
|
} else if (theResource != null && theResource.getMeta() != null && isNotBlank(theResource.getMeta().getVersionId())) {
|
||||||
response.addHeader(Constants.HEADER_ETAG, "W/\"" + theResource.getMeta().getVersionId() + '"');
|
String versionId = theResource.getMeta().getVersionId();
|
||||||
|
response.addHeader(Constants.HEADER_ETAG, createEtag(versionId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -739,6 +741,10 @@ public class RestfulServerUtils {
|
||||||
return response.sendWriterResponse(theStatusCode, contentType, charset, writer);
|
return response.sendWriterResponse(theStatusCode, contentType, charset, writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String createEtag(String theVersionId) {
|
||||||
|
return "W/\"" + theVersionId + '"';
|
||||||
|
}
|
||||||
|
|
||||||
public static Integer tryToExtractNamedParameter(RequestDetails theRequest, String theParamName) {
|
public static Integer tryToExtractNamedParameter(RequestDetails theRequest, String theParamName) {
|
||||||
String[] retVal = theRequest.getParameters().get(theParamName);
|
String[] retVal = theRequest.getParameters().get(theParamName);
|
||||||
if (retVal == null) {
|
if (retVal == null) {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor.Verdict
|
||||||
import ca.uhn.fhir.util.BundleUtil;
|
import ca.uhn.fhir.util.BundleUtil;
|
||||||
import ca.uhn.fhir.util.BundleUtil.BundleEntryParts;
|
import ca.uhn.fhir.util.BundleUtil.BundleEntryParts;
|
||||||
import ca.uhn.fhir.util.FhirTerser;
|
import ca.uhn.fhir.util.FhirTerser;
|
||||||
import org.apache.commons.codec.binary.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||||
|
@ -19,7 +19,6 @@ import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -376,7 +375,7 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
|
||||||
String compartmentOwnerResourceType = next.getResourceType();
|
String compartmentOwnerResourceType = next.getResourceType();
|
||||||
if (!StringUtils.equals(appliesToResourceType, compartmentOwnerResourceType)) {
|
if (!StringUtils.equals(appliesToResourceType, compartmentOwnerResourceType)) {
|
||||||
List<RuntimeSearchParam> params = sourceDef.getSearchParamsForCompartmentName(compartmentOwnerResourceType);
|
List<RuntimeSearchParam> params = sourceDef.getSearchParamsForCompartmentName(compartmentOwnerResourceType);
|
||||||
if (params.isEmpty() == false) {
|
if (!params.isEmpty()) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is a search, we can at least check whether
|
* If this is a search, we can at least check whether
|
||||||
|
|
|
@ -96,6 +96,12 @@ public class SearchParameter extends BaseQueryParameter {
|
||||||
ourParamTypes.put(HasParam.class, RestSearchParameterTypeEnum.HAS);
|
ourParamTypes.put(HasParam.class, RestSearchParameterTypeEnum.HAS);
|
||||||
ourParamTypes.put(HasOrListParam.class, RestSearchParameterTypeEnum.HAS);
|
ourParamTypes.put(HasOrListParam.class, RestSearchParameterTypeEnum.HAS);
|
||||||
ourParamTypes.put(HasAndListParam.class, RestSearchParameterTypeEnum.HAS);
|
ourParamTypes.put(HasAndListParam.class, RestSearchParameterTypeEnum.HAS);
|
||||||
|
|
||||||
|
ourParamTypes.put(SpecialParam.class, RestSearchParameterTypeEnum.SPECIAL);
|
||||||
|
ourParamTypes.put(SpecialOrListParam.class, RestSearchParameterTypeEnum.SPECIAL);
|
||||||
|
ourParamTypes.put(SpecialAndListParam.class, RestSearchParameterTypeEnum.SPECIAL);
|
||||||
|
ourParamQualifiers.put(RestSearchParameterTypeEnum.SPECIAL, CollectionUtil.newSet(Constants.PARAMQUALIFIER_MISSING));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Class<? extends IQueryParameterType>> myCompositeTypes = Collections.emptyList();
|
private List<Class<? extends IQueryParameterType>> myCompositeTypes = Collections.emptyList();
|
||||||
|
|
|
@ -802,7 +802,7 @@ public class JsonParserDstu2_1Test {
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
assertThat(encoded, containsString("Patient"));
|
assertThat(encoded, containsString("Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder(ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_SYSTEM, ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_CODE));
|
assertThat(encoded, stringContainsInOrder(ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_SYSTEM_DSTU3, ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_CODE));
|
||||||
assertThat(encoded, not(containsString("text")));
|
assertThat(encoded, not(containsString("text")));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
assertThat(encoded, containsString("family"));
|
assertThat(encoded, containsString("family"));
|
||||||
|
@ -836,7 +836,7 @@ public class JsonParserDstu2_1Test {
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
assertThat(encoded, containsString("Patient"));
|
assertThat(encoded, containsString("Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder("\"tag\"", "\"system\": \"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_SYSTEM + "\",", "\"code\": \"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_CODE + "\""));
|
assertThat(encoded, stringContainsInOrder("\"tag\"", "\"system\": \"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\",", "\"code\": \"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_CODE + "\""));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
assertThat(encoded, containsString("family"));
|
assertThat(encoded, containsString("family"));
|
||||||
assertThat(encoded, not(containsString("maritalStatus")));
|
assertThat(encoded, not(containsString("maritalStatus")));
|
||||||
|
@ -856,7 +856,7 @@ public class JsonParserDstu2_1Test {
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
assertThat(encoded, containsString("Patient"));
|
assertThat(encoded, containsString("Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder("\"tag\"", "\"system\": \"foo\",", "\"code\": \"bar\"", "\"system\": \"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_SYSTEM + "\"",
|
assertThat(encoded, stringContainsInOrder("\"tag\"", "\"system\": \"foo\",", "\"code\": \"bar\"", "\"system\": \"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\"",
|
||||||
"\"code\": \"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_CODE + "\""));
|
"\"code\": \"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_CODE + "\""));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
assertThat(encoded, containsString("family"));
|
assertThat(encoded, containsString("family"));
|
||||||
|
|
|
@ -1362,7 +1362,7 @@ public class XmlParserDstu2_1Test {
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
assertThat(encoded, containsString("<Patient"));
|
assertThat(encoded, containsString("<Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + Constants.TAG_SUBSETTED_SYSTEM + "\"/>", "<code value=\"" + Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\"/>", "<code value=\"" + Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
||||||
assertThat(encoded, not(containsString("text")));
|
assertThat(encoded, not(containsString("text")));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
assertThat(encoded, containsString("family"));
|
assertThat(encoded, containsString("family"));
|
||||||
|
@ -1462,7 +1462,7 @@ public class XmlParserDstu2_1Test {
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
assertThat(encoded, containsString("<Patient"));
|
assertThat(encoded, containsString("<Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + Constants.TAG_SUBSETTED_SYSTEM + "\"/>", "<code value=\"" + Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\"/>", "<code value=\"" + Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
assertThat(encoded, containsString("family"));
|
assertThat(encoded, containsString("family"));
|
||||||
assertThat(encoded, not(containsString("maritalStatus")));
|
assertThat(encoded, not(containsString("maritalStatus")));
|
||||||
|
@ -1483,7 +1483,7 @@ public class XmlParserDstu2_1Test {
|
||||||
|
|
||||||
assertThat(encoded, containsString("<Patient"));
|
assertThat(encoded, containsString("<Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"foo\"/>", "<code value=\"bar\"/>", "</tag>"));
|
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"foo\"/>", "<code value=\"bar\"/>", "</tag>"));
|
||||||
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + Constants.TAG_SUBSETTED_SYSTEM + "\"/>", "<code value=\"" + Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\"/>", "<code value=\"" + Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
assertThat(encoded, containsString("family"));
|
assertThat(encoded, containsString("family"));
|
||||||
assertThat(encoded, not(containsString("maritalStatus")));
|
assertThat(encoded, not(containsString("maritalStatus")));
|
||||||
|
|
|
@ -478,7 +478,7 @@ public class GenericClientDstu2_1Test {
|
||||||
client.read().resource(Patient.class).withId("1").execute();
|
client.read().resource(Patient.class).withId("1").execute();
|
||||||
fail();
|
fail();
|
||||||
} catch (FhirClientConnectionException e) {
|
} catch (FhirClientConnectionException e) {
|
||||||
assertEquals("java.lang.IllegalStateException", e.getMessage());
|
assertEquals(null, e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -808,7 +808,7 @@ public class JsonParserDstu2Test {
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
assertThat(encoded, containsString("Patient"));
|
assertThat(encoded, containsString("Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder(Constants.TAG_SUBSETTED_SYSTEM, Constants.TAG_SUBSETTED_CODE));
|
assertThat(encoded, stringContainsInOrder(Constants.TAG_SUBSETTED_SYSTEM_DSTU3, Constants.TAG_SUBSETTED_CODE));
|
||||||
assertThat(encoded, not(containsString("text")));
|
assertThat(encoded, not(containsString("text")));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
assertThat(encoded, containsString("family"));
|
assertThat(encoded, containsString("family"));
|
||||||
|
@ -918,7 +918,7 @@ public class JsonParserDstu2Test {
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
assertThat(encoded, containsString("Patient"));
|
assertThat(encoded, containsString("Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder("\"tag\"", "\"system\": \"" + Constants.TAG_SUBSETTED_SYSTEM + "\",", "\"code\": \"" + Constants.TAG_SUBSETTED_CODE + "\","));
|
assertThat(encoded, stringContainsInOrder("\"tag\"", "\"system\": \"" + Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\",", "\"code\": \"" + Constants.TAG_SUBSETTED_CODE + "\","));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
assertThat(encoded, containsString("family"));
|
assertThat(encoded, containsString("family"));
|
||||||
assertThat(encoded, not(containsString("maritalStatus")));
|
assertThat(encoded, not(containsString("maritalStatus")));
|
||||||
|
@ -940,7 +940,7 @@ public class JsonParserDstu2Test {
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
assertThat(encoded, containsString("Patient"));
|
assertThat(encoded, containsString("Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder("\"tag\"", "\"system\": \"foo\",", "\"code\": \"bar\"", "\"system\": \"" + Constants.TAG_SUBSETTED_SYSTEM + "\",",
|
assertThat(encoded, stringContainsInOrder("\"tag\"", "\"system\": \"foo\",", "\"code\": \"bar\"", "\"system\": \"" + Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\",",
|
||||||
"\"code\": \"" + Constants.TAG_SUBSETTED_CODE + "\","));
|
"\"code\": \"" + Constants.TAG_SUBSETTED_CODE + "\","));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
assertThat(encoded, containsString("family"));
|
assertThat(encoded, containsString("family"));
|
||||||
|
|
|
@ -22,7 +22,6 @@ import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.ArgumentMatchers;
|
import org.mockito.ArgumentMatchers;
|
||||||
import org.mockito.Matchers;
|
|
||||||
import org.mockito.internal.stubbing.answers.ThrowsException;
|
import org.mockito.internal.stubbing.answers.ThrowsException;
|
||||||
import org.xmlunit.builder.DiffBuilder;
|
import org.xmlunit.builder.DiffBuilder;
|
||||||
import org.xmlunit.builder.Input;
|
import org.xmlunit.builder.Input;
|
||||||
|
@ -1544,7 +1543,7 @@ public class XmlParserDstu2Test {
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
assertThat(encoded, containsString("<Patient"));
|
assertThat(encoded, containsString("<Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + Constants.TAG_SUBSETTED_SYSTEM + "\"/>", "<code value=\"" + Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\"/>", "<code value=\"" + Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
||||||
assertThat(encoded, not(containsString("text")));
|
assertThat(encoded, not(containsString("text")));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
assertThat(encoded, containsString("family"));
|
assertThat(encoded, containsString("family"));
|
||||||
|
@ -1658,7 +1657,7 @@ public class XmlParserDstu2Test {
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
assertThat(encoded, containsString("<Patient"));
|
assertThat(encoded, containsString("<Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + Constants.TAG_SUBSETTED_SYSTEM + "\"/>", "<code value=\"" + Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\"/>", "<code value=\"" + Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
assertThat(encoded, containsString("family"));
|
assertThat(encoded, containsString("family"));
|
||||||
assertThat(encoded, not(containsString("maritalStatus")));
|
assertThat(encoded, not(containsString("maritalStatus")));
|
||||||
|
@ -1681,7 +1680,7 @@ public class XmlParserDstu2Test {
|
||||||
|
|
||||||
assertThat(encoded, containsString("<Patient"));
|
assertThat(encoded, containsString("<Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"foo\"/>", "<code value=\"bar\"/>", "</tag>"));
|
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"foo\"/>", "<code value=\"bar\"/>", "</tag>"));
|
||||||
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + Constants.TAG_SUBSETTED_SYSTEM + "\"/>", "<code value=\"" + Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\"/>", "<code value=\"" + Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
assertThat(encoded, containsString("family"));
|
assertThat(encoded, containsString("family"));
|
||||||
assertThat(encoded, not(containsString("maritalStatus")));
|
assertThat(encoded, not(containsString("maritalStatus")));
|
||||||
|
|
|
@ -195,7 +195,9 @@ public interface IWorkerContext {
|
||||||
* @throws FHIRException
|
* @throws FHIRException
|
||||||
*/
|
*/
|
||||||
public ValueSetExpansionComponent expandVS(ConceptSetComponent inc, boolean heiarchical) throws TerminologyServiceException;
|
public ValueSetExpansionComponent expandVS(ConceptSetComponent inc, boolean heiarchical) throws TerminologyServiceException;
|
||||||
|
|
||||||
|
StructureDefinition fetchTypeDefinition(String theCode);
|
||||||
|
|
||||||
public class ValidationResult {
|
public class ValidationResult {
|
||||||
private ConceptDefinitionComponent definition;
|
private ConceptDefinitionComponent definition;
|
||||||
private IssueSeverity severity;
|
private IssueSeverity severity;
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.hl7.fhir.dstu3.terminologies.ValueSetExpanderFactory;
|
||||||
import org.hl7.fhir.dstu3.terminologies.ValueSetExpanderSimple;
|
import org.hl7.fhir.dstu3.terminologies.ValueSetExpanderSimple;
|
||||||
import org.hl7.fhir.dstu3.utils.INarrativeGenerator;
|
import org.hl7.fhir.dstu3.utils.INarrativeGenerator;
|
||||||
import org.hl7.fhir.exceptions.FHIRException;
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
|
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
||||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
@ -69,6 +70,8 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander
|
||||||
vso = getExpander().expand(theSource, theProfile);
|
vso = getExpander().expand(theSource, theProfile);
|
||||||
} catch (InvalidRequestException e) {
|
} catch (InvalidRequestException e) {
|
||||||
throw e;
|
throw e;
|
||||||
|
} catch (TerminologyServiceException e) {
|
||||||
|
throw new InvalidRequestException(e.getMessage(), e);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new InternalErrorException(e);
|
throw new InternalErrorException(e);
|
||||||
}
|
}
|
||||||
|
@ -89,6 +92,11 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander
|
||||||
return myValidationSupport.expandValueSet(myCtx, theInc);
|
return myValidationSupport.expandValueSet(myCtx, theInc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StructureDefinition fetchTypeDefinition(String theCode) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CodeSystem fetchCodeSystem(String theSystem) {
|
public CodeSystem fetchCodeSystem(String theSystem) {
|
||||||
if (myValidationSupport == null) {
|
if (myValidationSupport == null) {
|
||||||
|
@ -243,7 +251,7 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ValidationResult(null, null);
|
return new ValidationResult(IssueSeverity.ERROR, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,465 +1,461 @@
|
||||||
package org.hl7.fhir.dstu3.terminologies;
|
package org.hl7.fhir.dstu3.terminologies;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011+, HL7, Inc
|
* Copyright (c) 2011+, HL7, Inc
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
* are permitted provided that the following conditions are met:
|
* are permitted provided that the following conditions are met:
|
||||||
*
|
*
|
||||||
* Redistributions of source code must retain the above copyright notice, this
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
* list of conditions and the following disclaimer.
|
* list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright notice,
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
* and/or other materials provided with the distribution.
|
* and/or other materials provided with the distribution.
|
||||||
* Neither the name of HL7 nor the names of its contributors may be used to
|
* Neither the name of HL7 nor the names of its contributors may be used to
|
||||||
* endorse or promote products derived from this software without specific
|
* endorse or promote products derived from this software without specific
|
||||||
* prior written permission.
|
* prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.apache.commons.lang3.NotImplementedException;
|
import org.apache.commons.lang3.NotImplementedException;
|
||||||
import org.hl7.fhir.dstu3.context.IWorkerContext;
|
import org.hl7.fhir.dstu3.context.IWorkerContext;
|
||||||
import org.hl7.fhir.dstu3.model.CodeSystem;
|
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||||
import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
|
import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
|
||||||
import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
|
import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
|
||||||
import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionDesignationComponent;
|
import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionDesignationComponent;
|
||||||
import org.hl7.fhir.dstu3.model.DateTimeType;
|
import org.hl7.fhir.dstu3.model.DateTimeType;
|
||||||
import org.hl7.fhir.dstu3.model.ExpansionProfile;
|
import org.hl7.fhir.dstu3.model.ExpansionProfile;
|
||||||
import org.hl7.fhir.dstu3.model.Factory;
|
import org.hl7.fhir.dstu3.model.Factory;
|
||||||
import org.hl7.fhir.dstu3.model.PrimitiveType;
|
import org.hl7.fhir.dstu3.model.PrimitiveType;
|
||||||
import org.hl7.fhir.dstu3.model.Type;
|
import org.hl7.fhir.dstu3.model.Type;
|
||||||
import org.hl7.fhir.dstu3.model.UriType;
|
import org.hl7.fhir.dstu3.model.UriType;
|
||||||
import org.hl7.fhir.dstu3.model.ValueSet;
|
import org.hl7.fhir.dstu3.model.ValueSet;
|
||||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptReferenceComponent;
|
import org.hl7.fhir.dstu3.model.ValueSet.ConceptReferenceComponent;
|
||||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptReferenceDesignationComponent;
|
import org.hl7.fhir.dstu3.model.ValueSet.ConceptReferenceDesignationComponent;
|
||||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
||||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetFilterComponent;
|
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetFilterComponent;
|
||||||
import org.hl7.fhir.dstu3.model.ValueSet.FilterOperator;
|
import org.hl7.fhir.dstu3.model.ValueSet.FilterOperator;
|
||||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetComposeComponent;
|
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetComposeComponent;
|
||||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
|
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
|
||||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent;
|
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent;
|
||||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionParameterComponent;
|
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionParameterComponent;
|
||||||
import org.hl7.fhir.dstu3.utils.ToolingExtensions;
|
import org.hl7.fhir.dstu3.utils.ToolingExtensions;
|
||||||
import org.hl7.fhir.exceptions.FHIRException;
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||||
import org.hl7.fhir.exceptions.NoTerminologyServiceException;
|
import org.hl7.fhir.exceptions.NoTerminologyServiceException;
|
||||||
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
||||||
import org.hl7.fhir.utilities.Utilities;
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
|
|
||||||
public class ValueSetExpanderSimple implements ValueSetExpander {
|
public class ValueSetExpanderSimple implements ValueSetExpander {
|
||||||
|
|
||||||
private List<ValueSetExpansionContainsComponent> codes = new ArrayList<ValueSet.ValueSetExpansionContainsComponent>();
|
private List<ValueSetExpansionContainsComponent> codes = new ArrayList<ValueSet.ValueSetExpansionContainsComponent>();
|
||||||
private List<ValueSetExpansionContainsComponent> roots = new ArrayList<ValueSet.ValueSetExpansionContainsComponent>();
|
private List<ValueSetExpansionContainsComponent> roots = new ArrayList<ValueSet.ValueSetExpansionContainsComponent>();
|
||||||
private Map<String, ValueSetExpansionContainsComponent> map = new HashMap<String, ValueSet.ValueSetExpansionContainsComponent>();
|
private Map<String, ValueSetExpansionContainsComponent> map = new HashMap<String, ValueSet.ValueSetExpansionContainsComponent>();
|
||||||
private IWorkerContext context;
|
private IWorkerContext context;
|
||||||
private boolean canBeHeirarchy = true;
|
private boolean canBeHeirarchy = true;
|
||||||
private Set<String> excludeKeys = new HashSet<String>();
|
private Set<String> excludeKeys = new HashSet<String>();
|
||||||
private Set<String> excludeSystems = new HashSet<String>();
|
private Set<String> excludeSystems = new HashSet<String>();
|
||||||
private ValueSetExpanderFactory factory;
|
private ValueSetExpanderFactory factory;
|
||||||
private ValueSet focus;
|
private ValueSet focus;
|
||||||
private int maxExpansionSize = 500;
|
private int maxExpansionSize = 500;
|
||||||
|
|
||||||
private int total;
|
private int total;
|
||||||
|
|
||||||
public ValueSetExpanderSimple(IWorkerContext context, ValueSetExpanderFactory factory) {
|
public ValueSetExpanderSimple(IWorkerContext context, ValueSetExpanderFactory factory) {
|
||||||
super();
|
super();
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMaxExpansionSize(int theMaxExpansionSize) {
|
public void setMaxExpansionSize(int theMaxExpansionSize) {
|
||||||
maxExpansionSize = theMaxExpansionSize;
|
maxExpansionSize = theMaxExpansionSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ValueSetExpansionContainsComponent addCode(String system, String code, String display, ValueSetExpansionContainsComponent parent, List<ConceptDefinitionDesignationComponent> designations,
|
private ValueSetExpansionContainsComponent addCode(String system, String code, String display, ValueSetExpansionContainsComponent parent, List<ConceptDefinitionDesignationComponent> designations,
|
||||||
ExpansionProfile profile, boolean isAbstract, boolean inactive, List<ValueSet> filters) {
|
ExpansionProfile profile, boolean isAbstract, boolean inactive, List<ValueSet> filters) {
|
||||||
if (filters != null && !filters.isEmpty() && !filterContainsCode(filters, system, code))
|
if (filters != null && !filters.isEmpty() && !filterContainsCode(filters, system, code))
|
||||||
return null;
|
return null;
|
||||||
ValueSetExpansionContainsComponent n = new ValueSet.ValueSetExpansionContainsComponent();
|
ValueSetExpansionContainsComponent n = new ValueSet.ValueSetExpansionContainsComponent();
|
||||||
n.setSystem(system);
|
n.setSystem(system);
|
||||||
n.setCode(code);
|
n.setCode(code);
|
||||||
if (isAbstract)
|
if (isAbstract)
|
||||||
n.setAbstract(true);
|
n.setAbstract(true);
|
||||||
if (inactive)
|
if (inactive)
|
||||||
n.setInactive(true);
|
n.setInactive(true);
|
||||||
|
|
||||||
if (profile.getIncludeDesignations() && designations != null) {
|
if (profile.getIncludeDesignations() && designations != null) {
|
||||||
for (ConceptDefinitionDesignationComponent t : designations) {
|
for (ConceptDefinitionDesignationComponent t : designations) {
|
||||||
ToolingExtensions.addLanguageTranslation(n, t.getLanguage(), t.getValue());
|
ToolingExtensions.addLanguageTranslation(n, t.getLanguage(), t.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConceptDefinitionDesignationComponent t = profile.hasLanguage() ? getMatchingLang(designations, profile.getLanguage()) : null;
|
ConceptDefinitionDesignationComponent t = profile.hasLanguage() ? getMatchingLang(designations, profile.getLanguage()) : null;
|
||||||
if (t == null)
|
if (t == null)
|
||||||
n.setDisplay(display);
|
n.setDisplay(display);
|
||||||
else
|
else
|
||||||
n.setDisplay(t.getValue());
|
n.setDisplay(t.getValue());
|
||||||
|
|
||||||
String s = key(n);
|
String s = key(n);
|
||||||
if (map.containsKey(s) || excludeKeys.contains(s)) {
|
if (map.containsKey(s) || excludeKeys.contains(s)) {
|
||||||
canBeHeirarchy = false;
|
canBeHeirarchy = false;
|
||||||
} else {
|
} else {
|
||||||
codes.add(n);
|
codes.add(n);
|
||||||
map.put(s, n);
|
map.put(s, n);
|
||||||
total++;
|
total++;
|
||||||
}
|
}
|
||||||
if (canBeHeirarchy && parent != null) {
|
if (canBeHeirarchy && parent != null) {
|
||||||
parent.getContains().add(n);
|
parent.getContains().add(n);
|
||||||
} else {
|
} else {
|
||||||
roots.add(n);
|
roots.add(n);
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean filterContainsCode(List<ValueSet> filters, String system, String code) {
|
private boolean filterContainsCode(List<ValueSet> filters, String system, String code) {
|
||||||
for (ValueSet vse : filters)
|
for (ValueSet vse : filters)
|
||||||
if (expansionContainsCode(vse.getExpansion().getContains(), system, code))
|
if (expansionContainsCode(vse.getExpansion().getContains(), system, code))
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean expansionContainsCode(List<ValueSetExpansionContainsComponent> contains, String system, String code) {
|
private boolean expansionContainsCode(List<ValueSetExpansionContainsComponent> contains, String system, String code) {
|
||||||
for (ValueSetExpansionContainsComponent cc : contains) {
|
for (ValueSetExpansionContainsComponent cc : contains) {
|
||||||
if (system.equals(cc.getSystem()) && code.equals(cc.getCode()))
|
if (system.equals(cc.getSystem()) && code.equals(cc.getCode()))
|
||||||
return true;
|
return true;
|
||||||
if (expansionContainsCode(cc.getContains(), system, code))
|
if (expansionContainsCode(cc.getContains(), system, code))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConceptDefinitionDesignationComponent getMatchingLang(List<ConceptDefinitionDesignationComponent> list, String lang) {
|
private ConceptDefinitionDesignationComponent getMatchingLang(List<ConceptDefinitionDesignationComponent> list, String lang) {
|
||||||
for (ConceptDefinitionDesignationComponent t : list)
|
for (ConceptDefinitionDesignationComponent t : list)
|
||||||
if (t.getLanguage().equals(lang))
|
if (t.getLanguage().equals(lang))
|
||||||
return t;
|
return t;
|
||||||
for (ConceptDefinitionDesignationComponent t : list)
|
for (ConceptDefinitionDesignationComponent t : list)
|
||||||
if (t.getLanguage().startsWith(lang))
|
if (t.getLanguage().startsWith(lang))
|
||||||
return t;
|
return t;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addCodeAndDescendents(CodeSystem cs, String system, ConceptDefinitionComponent def, ValueSetExpansionContainsComponent parent, ExpansionProfile profile, List<ValueSet> filters)
|
private void addCodeAndDescendents(CodeSystem cs, String system, ConceptDefinitionComponent def, ValueSetExpansionContainsComponent parent, ExpansionProfile profile, List<ValueSet> filters)
|
||||||
throws FHIRException {
|
throws FHIRException {
|
||||||
if (!CodeSystemUtilities.isDeprecated(cs, def)) {
|
if (!CodeSystemUtilities.isDeprecated(cs, def)) {
|
||||||
ValueSetExpansionContainsComponent np = null;
|
ValueSetExpansionContainsComponent np = null;
|
||||||
boolean abs = CodeSystemUtilities.isNotSelectable(cs, def);
|
boolean abs = CodeSystemUtilities.isNotSelectable(cs, def);
|
||||||
boolean inc = CodeSystemUtilities.isInactive(cs, def);
|
boolean inc = CodeSystemUtilities.isInactive(cs, def);
|
||||||
if (canBeHeirarchy || !abs)
|
if (canBeHeirarchy || !abs)
|
||||||
np = addCode(system, def.getCode(), def.getDisplay(), parent, def.getDesignation(), profile, abs, inc, filters);
|
np = addCode(system, def.getCode(), def.getDisplay(), parent, def.getDesignation(), profile, abs, inc, filters);
|
||||||
for (ConceptDefinitionComponent c : def.getConcept())
|
for (ConceptDefinitionComponent c : def.getConcept())
|
||||||
addCodeAndDescendents(cs, system, c, np, profile, filters);
|
addCodeAndDescendents(cs, system, c, np, profile, filters);
|
||||||
} else
|
} else
|
||||||
for (ConceptDefinitionComponent c : def.getConcept())
|
for (ConceptDefinitionComponent c : def.getConcept())
|
||||||
addCodeAndDescendents(cs, system, c, null, profile, filters);
|
addCodeAndDescendents(cs, system, c, null, profile, filters);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addCodes(ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile, List<ValueSet> filters) throws ETooCostly {
|
private void addCodes(ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile, List<ValueSet> filters) throws ETooCostly {
|
||||||
if (expand.getContains().size() > maxExpansionSize)
|
if (expand.getContains().size() > maxExpansionSize)
|
||||||
throw new ETooCostly("Too many codes to display (>" + Integer.toString(expand.getContains().size()) + ")");
|
throw new ETooCostly("Too many codes to display (>" + Integer.toString(expand.getContains().size()) + ")");
|
||||||
for (ValueSetExpansionParameterComponent p : expand.getParameter()) {
|
for (ValueSetExpansionParameterComponent p : expand.getParameter()) {
|
||||||
if (!existsInParams(params, p.getName(), p.getValue()))
|
if (!existsInParams(params, p.getName(), p.getValue()))
|
||||||
params.add(p);
|
params.add(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
copyImportContains(expand.getContains(), null, profile, filters);
|
copyImportContains(expand.getContains(), null, profile, filters);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void excludeCode(String theSystem, String theCode) {
|
private void excludeCode(String theSystem, String theCode) {
|
||||||
ValueSetExpansionContainsComponent n = new ValueSet.ValueSetExpansionContainsComponent();
|
ValueSetExpansionContainsComponent n = new ValueSet.ValueSetExpansionContainsComponent();
|
||||||
n.setSystem(theSystem);
|
n.setSystem(theSystem);
|
||||||
n.setCode(theCode);
|
n.setCode(theCode);
|
||||||
String s = key(n);
|
String s = key(n);
|
||||||
excludeKeys.add(s);
|
excludeKeys.add(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void excludeCodes(ConceptSetComponent exc, List<ValueSetExpansionParameterComponent> params) throws TerminologyServiceException {
|
private void excludeCodes(ConceptSetComponent exc, List<ValueSetExpansionParameterComponent> params) throws TerminologyServiceException {
|
||||||
if (exc.hasSystem() && exc.getConcept().size() == 0 && exc.getFilter().size() == 0) {
|
if (exc.hasSystem() && exc.getConcept().size() == 0 && exc.getFilter().size() == 0) {
|
||||||
excludeSystems.add(exc.getSystem());
|
excludeSystems.add(exc.getSystem());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exc.hasValueSet())
|
if (exc.hasValueSet())
|
||||||
throw new Error("Processing Value set references in exclude is not yet done");
|
throw new Error("Processing Value set references in exclude is not yet done");
|
||||||
// importValueSet(imp.getValue(), params, profile);
|
// importValueSet(imp.getValue(), params, profile);
|
||||||
|
|
||||||
CodeSystem cs = context.fetchCodeSystem(exc.getSystem());
|
CodeSystem cs = context.fetchCodeSystem(exc.getSystem());
|
||||||
if ((cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) && context.supportsSystem(exc.getSystem())) {
|
if ((cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) && context.supportsSystem(exc.getSystem())) {
|
||||||
excludeCodes(context.expandVS(exc, false), params);
|
excludeCodes(context.expandVS(exc, false), params);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ConceptReferenceComponent c : exc.getConcept()) {
|
for (ConceptReferenceComponent c : exc.getConcept()) {
|
||||||
excludeCode(exc.getSystem(), c.getCode());
|
excludeCode(exc.getSystem(), c.getCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exc.getFilter().size() > 0)
|
if (exc.getFilter().size() > 0)
|
||||||
throw new NotImplementedException("not done yet");
|
throw new NotImplementedException("not done yet");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void excludeCodes(ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params) {
|
private void excludeCodes(ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params) {
|
||||||
for (ValueSetExpansionContainsComponent c : expand.getContains()) {
|
for (ValueSetExpansionContainsComponent c : expand.getContains()) {
|
||||||
excludeCode(c.getSystem(), c.getCode());
|
excludeCode(c.getSystem(), c.getCode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean existsInParams(List<ValueSetExpansionParameterComponent> params, String name, Type value) {
|
private boolean existsInParams(List<ValueSetExpansionParameterComponent> params, String name, Type value) {
|
||||||
for (ValueSetExpansionParameterComponent p : params) {
|
for (ValueSetExpansionParameterComponent p : params) {
|
||||||
if (p.getName().equals(name) && PrimitiveType.compareDeep(p.getValue(), value, false))
|
if (p.getName().equals(name) && PrimitiveType.compareDeep(p.getValue(), value, false))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueSetExpansionOutcome expand(ValueSet source, ExpansionProfile profile) {
|
public ValueSetExpansionOutcome expand(ValueSet source, ExpansionProfile profile) {
|
||||||
|
|
||||||
if (profile == null)
|
if (profile == null)
|
||||||
profile = makeDefaultExpansion();
|
profile = makeDefaultExpansion();
|
||||||
try {
|
try {
|
||||||
focus = source.copy();
|
focus = source.copy();
|
||||||
focus.setExpansion(new ValueSet.ValueSetExpansionComponent());
|
focus.setExpansion(new ValueSet.ValueSetExpansionComponent());
|
||||||
focus.getExpansion().setTimestampElement(DateTimeType.now());
|
focus.getExpansion().setTimestampElement(DateTimeType.now());
|
||||||
focus.getExpansion().setIdentifier(Factory.createUUID());
|
focus.getExpansion().setIdentifier(Factory.createUUID());
|
||||||
if (!profile.getUrl().startsWith("urn:uuid:"))
|
if (!profile.getUrl().startsWith("urn:uuid:"))
|
||||||
focus.getExpansion().addParameter().setName("profile").setValue(new UriType(profile.getUrl()));
|
focus.getExpansion().addParameter().setName("profile").setValue(new UriType(profile.getUrl()));
|
||||||
|
|
||||||
if (source.hasCompose())
|
if (source.hasCompose())
|
||||||
handleCompose(source.getCompose(), focus.getExpansion().getParameter(), profile);
|
handleCompose(source.getCompose(), focus.getExpansion().getParameter(), profile);
|
||||||
|
|
||||||
if (canBeHeirarchy) {
|
if (canBeHeirarchy) {
|
||||||
for (ValueSetExpansionContainsComponent c : roots) {
|
for (ValueSetExpansionContainsComponent c : roots) {
|
||||||
focus.getExpansion().getContains().add(c);
|
focus.getExpansion().getContains().add(c);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (ValueSetExpansionContainsComponent c : codes) {
|
for (ValueSetExpansionContainsComponent c : codes) {
|
||||||
if (map.containsKey(key(c)) && !c.getAbstract()) { // we may have added abstract codes earlier while we still thought it might be heirarchical, but later we gave up, so now ignore them
|
if (map.containsKey(key(c)) && !c.getAbstract()) { // we may have added abstract codes earlier while we still thought it might be heirarchical, but later we gave up, so now ignore them
|
||||||
focus.getExpansion().getContains().add(c);
|
focus.getExpansion().getContains().add(c);
|
||||||
c.getContains().clear(); // make sure any heirarchy is wiped
|
c.getContains().clear(); // make sure any heirarchy is wiped
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (total > 0) {
|
if (total > 0) {
|
||||||
focus.getExpansion().setTotal(total);
|
focus.getExpansion().setTotal(total);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ValueSetExpansionOutcome(focus);
|
return new ValueSetExpansionOutcome(focus);
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
// TODO: we should put something more specific instead of just Exception below, since
|
// TODO: we should put something more specific instead of just Exception below, since
|
||||||
// it swallows bugs.. what would be expected to be caught there?
|
// it swallows bugs.. what would be expected to be caught there?
|
||||||
throw e;
|
throw e;
|
||||||
} catch (NoTerminologyServiceException e) {
|
} catch (Exception e) {
|
||||||
// well, we couldn't expand, so we'll return an interface to a checker that can check membership of the set
|
// well, we couldn't expand, so we'll return an interface to a checker that can check membership of the set
|
||||||
// that might fail too, but it might not, later.
|
// that might fail too, but it might not, later.
|
||||||
return new ValueSetExpansionOutcome(new ValueSetCheckerSimple(source, factory, context), e.getMessage(), TerminologyServiceErrorClass.NOSERVICE);
|
return new ValueSetExpansionOutcome(new ValueSetCheckerSimple(source, factory, context), e.getMessage(), TerminologyServiceErrorClass.UNKNOWN);
|
||||||
} catch (Exception e) {
|
}
|
||||||
// well, we couldn't expand, so we'll return an interface to a checker that can check membership of the set
|
}
|
||||||
// that might fail too, but it might not, later.
|
|
||||||
return new ValueSetExpansionOutcome(new ValueSetCheckerSimple(source, factory, context), e.getMessage(), TerminologyServiceErrorClass.UNKNOWN);
|
private ExpansionProfile makeDefaultExpansion() {
|
||||||
}
|
ExpansionProfile res = new ExpansionProfile();
|
||||||
}
|
res.setUrl("urn:uuid:" + UUID.randomUUID().toString().toLowerCase());
|
||||||
|
res.setExcludeNested(true);
|
||||||
private ExpansionProfile makeDefaultExpansion() {
|
res.setIncludeDesignations(false);
|
||||||
ExpansionProfile res = new ExpansionProfile();
|
return res;
|
||||||
res.setUrl("urn:uuid:" + UUID.randomUUID().toString().toLowerCase());
|
}
|
||||||
res.setExcludeNested(true);
|
|
||||||
res.setIncludeDesignations(false);
|
private void addToHeirarchy(List<ValueSetExpansionContainsComponent> target, List<ValueSetExpansionContainsComponent> source) {
|
||||||
return res;
|
for (ValueSetExpansionContainsComponent s : source) {
|
||||||
}
|
target.add(s);
|
||||||
|
}
|
||||||
private void addToHeirarchy(List<ValueSetExpansionContainsComponent> target, List<ValueSetExpansionContainsComponent> source) {
|
}
|
||||||
for (ValueSetExpansionContainsComponent s : source) {
|
|
||||||
target.add(s);
|
private String getCodeDisplay(CodeSystem cs, String code) throws TerminologyServiceException {
|
||||||
}
|
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), code);
|
||||||
}
|
if (def == null)
|
||||||
|
throw new TerminologyServiceException("Unable to find code '" + code + "' in code system " + cs.getUrl());
|
||||||
private String getCodeDisplay(CodeSystem cs, String code) throws TerminologyServiceException {
|
return def.getDisplay();
|
||||||
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), code);
|
}
|
||||||
if (def == null)
|
|
||||||
throw new TerminologyServiceException("Unable to find code '" + code + "' in code system " + cs.getUrl());
|
private ConceptDefinitionComponent getConceptForCode(List<ConceptDefinitionComponent> clist, String code) {
|
||||||
return def.getDisplay();
|
for (ConceptDefinitionComponent c : clist) {
|
||||||
}
|
if (code.equals(c.getCode()))
|
||||||
|
return c;
|
||||||
private ConceptDefinitionComponent getConceptForCode(List<ConceptDefinitionComponent> clist, String code) {
|
ConceptDefinitionComponent v = getConceptForCode(c.getConcept(), code);
|
||||||
for (ConceptDefinitionComponent c : clist) {
|
if (v != null)
|
||||||
if (code.equals(c.getCode()))
|
return v;
|
||||||
return c;
|
}
|
||||||
ConceptDefinitionComponent v = getConceptForCode(c.getConcept(), code);
|
return null;
|
||||||
if (v != null)
|
}
|
||||||
return v;
|
|
||||||
}
|
private void handleCompose(ValueSetComposeComponent compose, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile)
|
||||||
return null;
|
throws ETooCostly, FileNotFoundException, IOException, FHIRException {
|
||||||
}
|
// Exclude comes first because we build up a map of things to exclude
|
||||||
|
for (ConceptSetComponent inc : compose.getExclude())
|
||||||
private void handleCompose(ValueSetComposeComponent compose, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile)
|
excludeCodes(inc, params);
|
||||||
throws ETooCostly, FileNotFoundException, IOException, FHIRException {
|
canBeHeirarchy = !profile.getExcludeNested() && excludeKeys.isEmpty() && excludeSystems.isEmpty();
|
||||||
// Exclude comes first because we build up a map of things to exclude
|
boolean first = true;
|
||||||
for (ConceptSetComponent inc : compose.getExclude())
|
for (ConceptSetComponent inc : compose.getInclude()) {
|
||||||
excludeCodes(inc, params);
|
if (first == true)
|
||||||
canBeHeirarchy = !profile.getExcludeNested() && excludeKeys.isEmpty() && excludeSystems.isEmpty();
|
first = false;
|
||||||
boolean first = true;
|
else
|
||||||
for (ConceptSetComponent inc : compose.getInclude()) {
|
canBeHeirarchy = false;
|
||||||
if (first == true)
|
includeCodes(inc, params, profile);
|
||||||
first = false;
|
}
|
||||||
else
|
|
||||||
canBeHeirarchy = false;
|
}
|
||||||
includeCodes(inc, params, profile);
|
|
||||||
}
|
private ValueSet importValueSet(String value, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile)
|
||||||
|
throws ETooCostly, TerminologyServiceException, FileNotFoundException, IOException, FHIRFormatError {
|
||||||
}
|
if (value == null)
|
||||||
|
throw new TerminologyServiceException("unable to find value set with no identity");
|
||||||
private ValueSet importValueSet(String value, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile)
|
ValueSet vs = context.fetchResource(ValueSet.class, value);
|
||||||
throws ETooCostly, TerminologyServiceException, FileNotFoundException, IOException, FHIRFormatError {
|
if (vs == null)
|
||||||
if (value == null)
|
throw new TerminologyServiceException("Unable to find imported value set " + value);
|
||||||
throw new TerminologyServiceException("unable to find value set with no identity");
|
ValueSetExpansionOutcome vso = factory.getExpander().expand(vs, profile);
|
||||||
ValueSet vs = context.fetchResource(ValueSet.class, value);
|
if (vso.getError() != null)
|
||||||
if (vs == null)
|
throw new TerminologyServiceException("Unable to expand imported value set: " + vso.getError());
|
||||||
throw new TerminologyServiceException("Unable to find imported value set " + value);
|
if (vso.getService() != null)
|
||||||
ValueSetExpansionOutcome vso = factory.getExpander().expand(vs, profile);
|
throw new TerminologyServiceException("Unable to expand imported value set " + value);
|
||||||
if (vso.getError() != null)
|
if (vs.hasVersion())
|
||||||
throw new TerminologyServiceException("Unable to expand imported value set: " + vso.getError());
|
if (!existsInParams(params, "version", new UriType(vs.getUrl() + "|" + vs.getVersion())))
|
||||||
if (vso.getService() != null)
|
params.add(new ValueSetExpansionParameterComponent().setName("version").setValue(new UriType(vs.getUrl() + "|" + vs.getVersion())));
|
||||||
throw new TerminologyServiceException("Unable to expand imported value set " + value);
|
for (ValueSetExpansionParameterComponent p : vso.getValueset().getExpansion().getParameter()) {
|
||||||
if (vs.hasVersion())
|
if (!existsInParams(params, p.getName(), p.getValue()))
|
||||||
if (!existsInParams(params, "version", new UriType(vs.getUrl() + "|" + vs.getVersion())))
|
params.add(p);
|
||||||
params.add(new ValueSetExpansionParameterComponent().setName("version").setValue(new UriType(vs.getUrl() + "|" + vs.getVersion())));
|
}
|
||||||
for (ValueSetExpansionParameterComponent p : vso.getValueset().getExpansion().getParameter()) {
|
canBeHeirarchy = false; // if we're importing a value set, we have to be combining, so we won't try for a heirarchy
|
||||||
if (!existsInParams(params, p.getName(), p.getValue()))
|
return vso.getValueset();
|
||||||
params.add(p);
|
}
|
||||||
}
|
|
||||||
canBeHeirarchy = false; // if we're importing a value set, we have to be combining, so we won't try for a heirarchy
|
private void copyImportContains(List<ValueSetExpansionContainsComponent> list, ValueSetExpansionContainsComponent parent, ExpansionProfile profile, List<ValueSet> filter) {
|
||||||
return vso.getValueset();
|
for (ValueSetExpansionContainsComponent c : list) {
|
||||||
}
|
ValueSetExpansionContainsComponent np = addCode(c.getSystem(), c.getCode(), c.getDisplay(), parent, null, profile, c.getAbstract(), c.getInactive(), filter);
|
||||||
|
copyImportContains(c.getContains(), np, profile, filter);
|
||||||
private void copyImportContains(List<ValueSetExpansionContainsComponent> list, ValueSetExpansionContainsComponent parent, ExpansionProfile profile, List<ValueSet> filter) {
|
}
|
||||||
for (ValueSetExpansionContainsComponent c : list) {
|
}
|
||||||
ValueSetExpansionContainsComponent np = addCode(c.getSystem(), c.getCode(), c.getDisplay(), parent, null, profile, c.getAbstract(), c.getInactive(), filter);
|
|
||||||
copyImportContains(c.getContains(), np, profile, filter);
|
private void includeCodes(ConceptSetComponent inc, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile) throws ETooCostly, FileNotFoundException, IOException, FHIRException {
|
||||||
}
|
List<ValueSet> imports = new ArrayList<ValueSet>();
|
||||||
}
|
for (UriType imp : inc.getValueSet())
|
||||||
|
imports.add(importValueSet(imp.getValue(), params, profile));
|
||||||
private void includeCodes(ConceptSetComponent inc, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile) throws ETooCostly, FileNotFoundException, IOException, FHIRException {
|
|
||||||
List<ValueSet> imports = new ArrayList<ValueSet>();
|
if (!inc.hasSystem()) {
|
||||||
for (UriType imp : inc.getValueSet())
|
if (imports.isEmpty()) // though this is not supposed to be the case
|
||||||
imports.add(importValueSet(imp.getValue(), params, profile));
|
return;
|
||||||
|
ValueSet base = imports.get(0);
|
||||||
if (!inc.hasSystem()) {
|
imports.remove(0);
|
||||||
if (imports.isEmpty()) // though this is not supposed to be the case
|
copyImportContains(base.getExpansion().getContains(), null, profile, imports);
|
||||||
return;
|
} else {
|
||||||
ValueSet base = imports.get(0);
|
CodeSystem cs = context.fetchCodeSystem(inc.getSystem());
|
||||||
imports.remove(0);
|
if ((cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) && context.supportsSystem(inc.getSystem())) {
|
||||||
copyImportContains(base.getExpansion().getContains(), null, profile, imports);
|
addCodes(context.expandVS(inc, canBeHeirarchy), params, profile, imports);
|
||||||
} else {
|
return;
|
||||||
CodeSystem cs = context.fetchCodeSystem(inc.getSystem());
|
}
|
||||||
if ((cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) && context.supportsSystem(inc.getSystem())) {
|
|
||||||
addCodes(context.expandVS(inc, canBeHeirarchy), params, profile, imports);
|
if (cs == null) {
|
||||||
return;
|
if (context.isNoTerminologyServer())
|
||||||
}
|
throw new NoTerminologyServiceException("unable to find code system " + inc.getSystem().toString());
|
||||||
|
else
|
||||||
if (cs == null) {
|
throw new TerminologyServiceException("unable to find code system " + inc.getSystem().toString());
|
||||||
if (context.isNoTerminologyServer())
|
}
|
||||||
throw new NoTerminologyServiceException("unable to find code system " + inc.getSystem().toString());
|
if (cs.getContent() != CodeSystemContentMode.COMPLETE)
|
||||||
else
|
throw new TerminologyServiceException("Code system " + inc.getSystem().toString() + " is incomplete");
|
||||||
throw new TerminologyServiceException("unable to find code system " + inc.getSystem().toString());
|
if (cs.hasVersion())
|
||||||
}
|
if (!existsInParams(params, "version", new UriType(cs.getUrl() + "|" + cs.getVersion())))
|
||||||
if (cs.getContent() != CodeSystemContentMode.COMPLETE)
|
params.add(new ValueSetExpansionParameterComponent().setName("version").setValue(new UriType(cs.getUrl() + "|" + cs.getVersion())));
|
||||||
throw new TerminologyServiceException("Code system " + inc.getSystem().toString() + " is incomplete");
|
|
||||||
if (cs.hasVersion())
|
if (inc.getConcept().size() == 0 && inc.getFilter().size() == 0) {
|
||||||
if (!existsInParams(params, "version", new UriType(cs.getUrl() + "|" + cs.getVersion())))
|
// special case - add all the code system
|
||||||
params.add(new ValueSetExpansionParameterComponent().setName("version").setValue(new UriType(cs.getUrl() + "|" + cs.getVersion())));
|
for (ConceptDefinitionComponent def : cs.getConcept()) {
|
||||||
|
addCodeAndDescendents(cs, inc.getSystem(), def, null, profile, imports);
|
||||||
if (inc.getConcept().size() == 0 && inc.getFilter().size() == 0) {
|
}
|
||||||
// special case - add all the code system
|
}
|
||||||
for (ConceptDefinitionComponent def : cs.getConcept()) {
|
|
||||||
addCodeAndDescendents(cs, inc.getSystem(), def, null, profile, imports);
|
if (!inc.getConcept().isEmpty()) {
|
||||||
}
|
canBeHeirarchy = false;
|
||||||
}
|
for (ConceptReferenceComponent c : inc.getConcept()) {
|
||||||
|
addCode(inc.getSystem(), c.getCode(), Utilities.noString(c.getDisplay()) ? getCodeDisplay(cs, c.getCode()) : c.getDisplay(), null, convertDesignations(c.getDesignation()), profile, false,
|
||||||
if (!inc.getConcept().isEmpty()) {
|
CodeSystemUtilities.isInactive(cs, c.getCode()), imports);
|
||||||
canBeHeirarchy = false;
|
}
|
||||||
for (ConceptReferenceComponent c : inc.getConcept()) {
|
}
|
||||||
addCode(inc.getSystem(), c.getCode(), Utilities.noString(c.getDisplay()) ? getCodeDisplay(cs, c.getCode()) : c.getDisplay(), null, convertDesignations(c.getDesignation()), profile, false,
|
if (inc.getFilter().size() > 1) {
|
||||||
CodeSystemUtilities.isInactive(cs, c.getCode()), imports);
|
canBeHeirarchy = false; // which will bt the case if we get around to supporting this
|
||||||
}
|
throw new TerminologyServiceException("Multiple filters not handled yet"); // need to and them, and this isn't done yet. But this shouldn't arise in non loinc and snomed value sets
|
||||||
}
|
}
|
||||||
if (inc.getFilter().size() > 1) {
|
if (inc.getFilter().size() == 1) {
|
||||||
canBeHeirarchy = false; // which will bt the case if we get around to supporting this
|
ConceptSetFilterComponent fc = inc.getFilter().get(0);
|
||||||
throw new TerminologyServiceException("Multiple filters not handled yet"); // need to and them, and this isn't done yet. But this shouldn't arise in non loinc and snomed value sets
|
if ("concept".equals(fc.getProperty()) && fc.getOp() == FilterOperator.ISA) {
|
||||||
}
|
// special: all codes in the target code system under the value
|
||||||
if (inc.getFilter().size() == 1) {
|
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue());
|
||||||
ConceptSetFilterComponent fc = inc.getFilter().get(0);
|
if (def == null)
|
||||||
if ("concept".equals(fc.getProperty()) && fc.getOp() == FilterOperator.ISA) {
|
throw new TerminologyServiceException("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
|
||||||
// special: all codes in the target code system under the value
|
addCodeAndDescendents(cs, inc.getSystem(), def, null, profile, imports);
|
||||||
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue());
|
} else if ("concept".equals(fc.getProperty()) && fc.getOp() == FilterOperator.DESCENDENTOF) {
|
||||||
if (def == null)
|
// special: all codes in the target code system under the value
|
||||||
throw new TerminologyServiceException("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
|
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue());
|
||||||
addCodeAndDescendents(cs, inc.getSystem(), def, null, profile, imports);
|
if (def == null)
|
||||||
} else if ("concept".equals(fc.getProperty()) && fc.getOp() == FilterOperator.DESCENDENTOF) {
|
throw new TerminologyServiceException("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
|
||||||
// special: all codes in the target code system under the value
|
for (ConceptDefinitionComponent c : def.getConcept())
|
||||||
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue());
|
addCodeAndDescendents(cs, inc.getSystem(), c, null, profile, imports);
|
||||||
if (def == null)
|
} else if ("display".equals(fc.getProperty()) && fc.getOp() == FilterOperator.EQUAL) {
|
||||||
throw new TerminologyServiceException("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
|
// gg; note: wtf is this: if the filter is display=v, look up the code 'v', and see if it's diplsay is 'v'?
|
||||||
for (ConceptDefinitionComponent c : def.getConcept())
|
canBeHeirarchy = false;
|
||||||
addCodeAndDescendents(cs, inc.getSystem(), c, null, profile, imports);
|
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue());
|
||||||
} else if ("display".equals(fc.getProperty()) && fc.getOp() == FilterOperator.EQUAL) {
|
if (def != null) {
|
||||||
// gg; note: wtf is this: if the filter is display=v, look up the code 'v', and see if it's diplsay is 'v'?
|
if (isNotBlank(def.getDisplay()) && isNotBlank(fc.getValue())) {
|
||||||
canBeHeirarchy = false;
|
if (def.getDisplay().contains(fc.getValue())) {
|
||||||
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue());
|
addCode(inc.getSystem(), def.getCode(), def.getDisplay(), null, def.getDesignation(), profile, CodeSystemUtilities.isNotSelectable(cs, def), CodeSystemUtilities.isInactive(cs, def),
|
||||||
if (def != null) {
|
imports);
|
||||||
if (isNotBlank(def.getDisplay()) && isNotBlank(fc.getValue())) {
|
}
|
||||||
if (def.getDisplay().contains(fc.getValue())) {
|
}
|
||||||
addCode(inc.getSystem(), def.getCode(), def.getDisplay(), null, def.getDesignation(), profile, CodeSystemUtilities.isNotSelectable(cs, def), CodeSystemUtilities.isInactive(cs, def),
|
}
|
||||||
imports);
|
} else
|
||||||
}
|
throw new NotImplementedException("Search by property[" + fc.getProperty() + "] and op[" + fc.getOp() + "] is not supported yet");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
throw new NotImplementedException("Search by property[" + fc.getProperty() + "] and op[" + fc.getOp() + "] is not supported yet");
|
|
||||||
}
|
private List<ConceptDefinitionDesignationComponent> convertDesignations(List<ConceptReferenceDesignationComponent> list) {
|
||||||
}
|
List<ConceptDefinitionDesignationComponent> res = new ArrayList<CodeSystem.ConceptDefinitionDesignationComponent>();
|
||||||
}
|
for (ConceptReferenceDesignationComponent t : list) {
|
||||||
|
ConceptDefinitionDesignationComponent c = new ConceptDefinitionDesignationComponent();
|
||||||
private List<ConceptDefinitionDesignationComponent> convertDesignations(List<ConceptReferenceDesignationComponent> list) {
|
c.setLanguage(t.getLanguage());
|
||||||
List<ConceptDefinitionDesignationComponent> res = new ArrayList<CodeSystem.ConceptDefinitionDesignationComponent>();
|
c.setUse(t.getUse());
|
||||||
for (ConceptReferenceDesignationComponent t : list) {
|
c.setValue(t.getValue());
|
||||||
ConceptDefinitionDesignationComponent c = new ConceptDefinitionDesignationComponent();
|
}
|
||||||
c.setLanguage(t.getLanguage());
|
return res;
|
||||||
c.setUse(t.getUse());
|
}
|
||||||
c.setValue(t.getValue());
|
|
||||||
}
|
private String key(String uri, String code) {
|
||||||
return res;
|
return "{" + uri + "}" + code;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String key(String uri, String code) {
|
private String key(ValueSetExpansionContainsComponent c) {
|
||||||
return "{" + uri + "}" + code;
|
return key(c.getSystem(), c.getCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
private String key(ValueSetExpansionContainsComponent c) {
|
}
|
||||||
return key(c.getSystem(), c.getCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -13,6 +13,7 @@ import org.eclipse.jetty.servlet.ServletHandler;
|
||||||
import org.eclipse.jetty.servlet.ServletHolder;
|
import org.eclipse.jetty.servlet.ServletHolder;
|
||||||
import org.hl7.fhir.dstu3.model.*;
|
import org.hl7.fhir.dstu3.model.*;
|
||||||
import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
|
import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
|
||||||
|
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
|
||||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
|
@ -177,7 +178,7 @@ public class ContextScanningDstu3Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Read
|
@Read
|
||||||
public Observation read(@IdParam IdType theId) {
|
public Observation read(@IdParam IdType theId) throws FHIRFormatError {
|
||||||
Observation retVal = new Observation();
|
Observation retVal = new Observation();
|
||||||
retVal.setId(theId);
|
retVal.setId(theId);
|
||||||
retVal.addIdentifier().setSystem("ISYS").setValue("IVAL");
|
retVal.addIdentifier().setSystem("ISYS").setValue("IVAL");
|
||||||
|
|
|
@ -1023,7 +1023,7 @@ public class JsonParserDstu3Test {
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
assertThat(encoded, containsString("Patient"));
|
assertThat(encoded, containsString("Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder(ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_SYSTEM, ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_CODE));
|
assertThat(encoded, stringContainsInOrder(ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_SYSTEM_DSTU3, ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_CODE));
|
||||||
assertThat(encoded, not(containsString("text")));
|
assertThat(encoded, not(containsString("text")));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
assertThat(encoded, containsString("family"));
|
assertThat(encoded, containsString("family"));
|
||||||
|
@ -1057,7 +1057,7 @@ public class JsonParserDstu3Test {
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
assertThat(encoded, containsString("Patient"));
|
assertThat(encoded, containsString("Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder("\"tag\"", "\"system\": \"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_SYSTEM + "\",", "\"code\": \"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_CODE + "\""));
|
assertThat(encoded, stringContainsInOrder("\"tag\"", "\"system\": \"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\",", "\"code\": \"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_CODE + "\""));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
assertThat(encoded, containsString("family"));
|
assertThat(encoded, containsString("family"));
|
||||||
assertThat(encoded, not(containsString("maritalStatus")));
|
assertThat(encoded, not(containsString("maritalStatus")));
|
||||||
|
@ -1077,7 +1077,7 @@ public class JsonParserDstu3Test {
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
assertThat(encoded, containsString("Patient"));
|
assertThat(encoded, containsString("Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder("\"tag\"", "\"system\": \"foo\",", "\"code\": \"bar\"", "\"system\": \"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_SYSTEM + "\"",
|
assertThat(encoded, stringContainsInOrder("\"tag\"", "\"system\": \"foo\",", "\"code\": \"bar\"", "\"system\": \"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\"",
|
||||||
"\"code\": \"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_CODE + "\""));
|
"\"code\": \"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_CODE + "\""));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
assertThat(encoded, containsString("family"));
|
assertThat(encoded, containsString("family"));
|
||||||
|
|
|
@ -1519,7 +1519,7 @@ public class XmlParserDstu3Test {
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
assertThat(encoded, containsString("<Patient"));
|
assertThat(encoded, containsString("<Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_SYSTEM + "\"/>",
|
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\"/>",
|
||||||
"<code value=\"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
"<code value=\"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
||||||
assertThat(encoded, not(containsString("text")));
|
assertThat(encoded, not(containsString("text")));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
|
@ -1666,7 +1666,7 @@ public class XmlParserDstu3Test {
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
assertThat(encoded, containsString("<Patient"));
|
assertThat(encoded, containsString("<Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_SYSTEM + "\"/>",
|
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\"/>",
|
||||||
"<code value=\"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
"<code value=\"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
assertThat(encoded, containsString("family"));
|
assertThat(encoded, containsString("family"));
|
||||||
|
@ -1688,7 +1688,7 @@ public class XmlParserDstu3Test {
|
||||||
|
|
||||||
assertThat(encoded, containsString("<Patient"));
|
assertThat(encoded, containsString("<Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"foo\"/>", "<code value=\"bar\"/>", "</tag>"));
|
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"foo\"/>", "<code value=\"bar\"/>", "</tag>"));
|
||||||
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_SYSTEM + "\"/>",
|
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\"/>",
|
||||||
"<code value=\"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
"<code value=\"" + ca.uhn.fhir.rest.api.Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
assertThat(encoded, containsString("family"));
|
assertThat(encoded, containsString("family"));
|
||||||
|
|
|
@ -504,7 +504,7 @@ public class GenericClientDstu3Test {
|
||||||
client.read().resource(Patient.class).withId("1").execute();
|
client.read().resource(Patient.class).withId("1").execute();
|
||||||
fail();
|
fail();
|
||||||
} catch (FhirClientConnectionException e) {
|
} catch (FhirClientConnectionException e) {
|
||||||
assertEquals("java.lang.IllegalStateException", e.getMessage());
|
assertEquals(null, e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3,7 +3,6 @@ package ca.uhn.fhir.parser;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.model.api.annotation.Child;
|
import ca.uhn.fhir.model.api.annotation.Child;
|
||||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||||
import ca.uhn.fhir.narrative.INarrativeGenerator;
|
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
import net.sf.json.JSON;
|
import net.sf.json.JSON;
|
||||||
|
@ -22,16 +21,13 @@ import org.hl7.fhir.instance.model.Narrative.NarrativeStatus;
|
||||||
import org.hl7.fhir.instance.model.Patient.ContactComponent;
|
import org.hl7.fhir.instance.model.Patient.ContactComponent;
|
||||||
import org.hl7.fhir.instance.model.ValueSet.ConceptDefinitionComponent;
|
import org.hl7.fhir.instance.model.ValueSet.ConceptDefinitionComponent;
|
||||||
import org.hl7.fhir.instance.model.ValueSet.ValueSetCodeSystemComponent;
|
import org.hl7.fhir.instance.model.ValueSet.ValueSetCodeSystemComponent;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.instance.model.api.INarrative;
|
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -148,7 +144,7 @@ public class JsonParserHl7OrgDstu2Test {
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
assertThat(encoded, containsString("Patient"));
|
assertThat(encoded, containsString("Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder(Constants.TAG_SUBSETTED_SYSTEM, Constants.TAG_SUBSETTED_CODE));
|
assertThat(encoded, stringContainsInOrder(Constants.TAG_SUBSETTED_SYSTEM_DSTU3, Constants.TAG_SUBSETTED_CODE));
|
||||||
assertThat(encoded, not(containsString("text")));
|
assertThat(encoded, not(containsString("text")));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
assertThat(encoded, containsString("family"));
|
assertThat(encoded, containsString("family"));
|
||||||
|
@ -780,7 +776,7 @@ public class JsonParserHl7OrgDstu2Test {
|
||||||
|
|
||||||
assertThat(encoded, containsString("Patient"));
|
assertThat(encoded, containsString("Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder("\"tag\"",
|
assertThat(encoded, stringContainsInOrder("\"tag\"",
|
||||||
"\"system\": \"" + Constants.TAG_SUBSETTED_SYSTEM + "\",", "\"code\": \"" + Constants.TAG_SUBSETTED_CODE+"\","));
|
"\"system\": \"" + Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\",", "\"code\": \"" + Constants.TAG_SUBSETTED_CODE+"\","));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
assertThat(encoded, containsString("family"));
|
assertThat(encoded, containsString("family"));
|
||||||
assertThat(encoded, not(containsString("maritalStatus")));
|
assertThat(encoded, not(containsString("maritalStatus")));
|
||||||
|
@ -802,7 +798,7 @@ public class JsonParserHl7OrgDstu2Test {
|
||||||
assertThat(encoded, containsString("Patient"));
|
assertThat(encoded, containsString("Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder("\"tag\"",
|
assertThat(encoded, stringContainsInOrder("\"tag\"",
|
||||||
"\"system\": \"foo\",", "\"code\": \"bar\"",
|
"\"system\": \"foo\",", "\"code\": \"bar\"",
|
||||||
"\"system\": \"" + Constants.TAG_SUBSETTED_SYSTEM + "\",", "\"code\": \"" + Constants.TAG_SUBSETTED_CODE+"\","));
|
"\"system\": \"" + Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\",", "\"code\": \"" + Constants.TAG_SUBSETTED_CODE+"\","));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
assertThat(encoded, containsString("family"));
|
assertThat(encoded, containsString("family"));
|
||||||
assertThat(encoded, not(containsString("maritalStatus")));
|
assertThat(encoded, not(containsString("maritalStatus")));
|
||||||
|
|
|
@ -19,8 +19,6 @@ import org.hl7.fhir.instance.model.Enumeration;
|
||||||
import org.hl7.fhir.instance.model.Enumerations.AdministrativeGender;
|
import org.hl7.fhir.instance.model.Enumerations.AdministrativeGender;
|
||||||
import org.hl7.fhir.instance.model.Identifier.IdentifierUse;
|
import org.hl7.fhir.instance.model.Identifier.IdentifierUse;
|
||||||
import org.hl7.fhir.instance.model.Narrative.NarrativeStatus;
|
import org.hl7.fhir.instance.model.Narrative.NarrativeStatus;
|
||||||
import org.hl7.fhir.instance.model.api.*;
|
|
||||||
import org.junit.*;
|
|
||||||
import org.hl7.fhir.instance.model.Observation;
|
import org.hl7.fhir.instance.model.Observation;
|
||||||
import org.hl7.fhir.instance.model.Organization;
|
import org.hl7.fhir.instance.model.Organization;
|
||||||
import org.hl7.fhir.instance.model.Patient;
|
import org.hl7.fhir.instance.model.Patient;
|
||||||
|
@ -32,7 +30,6 @@ import org.hl7.fhir.instance.model.Specimen;
|
||||||
import org.hl7.fhir.instance.model.StringType;
|
import org.hl7.fhir.instance.model.StringType;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.instance.model.api.INarrative;
|
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
@ -49,7 +46,6 @@ import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.api.AddProfileTagEnum;
|
import ca.uhn.fhir.context.api.AddProfileTagEnum;
|
||||||
import ca.uhn.fhir.model.api.annotation.Child;
|
import ca.uhn.fhir.model.api.annotation.Child;
|
||||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||||
import ca.uhn.fhir.narrative.INarrativeGenerator;
|
|
||||||
import ca.uhn.fhir.parser.JsonParserHl7OrgDstu2Test.MyPatientWithOneDeclaredAddressExtension;
|
import ca.uhn.fhir.parser.JsonParserHl7OrgDstu2Test.MyPatientWithOneDeclaredAddressExtension;
|
||||||
import ca.uhn.fhir.parser.JsonParserHl7OrgDstu2Test.MyPatientWithOneDeclaredExtension;
|
import ca.uhn.fhir.parser.JsonParserHl7OrgDstu2Test.MyPatientWithOneDeclaredExtension;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
|
@ -1050,7 +1046,7 @@ public class XmlParserHl7OrgDstu2Test {
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
assertThat(encoded, containsString("<Patient"));
|
assertThat(encoded, containsString("<Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + Constants.TAG_SUBSETTED_SYSTEM + "\"/>",
|
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\"/>",
|
||||||
"<code value=\"" + Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
"<code value=\"" + Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
||||||
assertThat(encoded, not(containsString("text")));
|
assertThat(encoded, not(containsString("text")));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
|
@ -1169,7 +1165,7 @@ public class XmlParserHl7OrgDstu2Test {
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
assertThat(encoded, containsString("<Patient"));
|
assertThat(encoded, containsString("<Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + Constants.TAG_SUBSETTED_SYSTEM + "\"/>",
|
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\"/>",
|
||||||
"<code value=\"" + Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
"<code value=\"" + Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
assertThat(encoded, containsString("family"));
|
assertThat(encoded, containsString("family"));
|
||||||
|
@ -1191,7 +1187,7 @@ public class XmlParserHl7OrgDstu2Test {
|
||||||
|
|
||||||
assertThat(encoded, containsString("<Patient"));
|
assertThat(encoded, containsString("<Patient"));
|
||||||
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"foo\"/>", "<code value=\"bar\"/>", "</tag>"));
|
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"foo\"/>", "<code value=\"bar\"/>", "</tag>"));
|
||||||
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + Constants.TAG_SUBSETTED_SYSTEM + "\"/>",
|
assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\"/>",
|
||||||
"<code value=\"" + Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
"<code value=\"" + Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
|
||||||
assertThat(encoded, not(containsString("THE DIV")));
|
assertThat(encoded, not(containsString("THE DIV")));
|
||||||
assertThat(encoded, containsString("family"));
|
assertThat(encoded, containsString("family"));
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
package org.hl7.fhir.r4.conformance;
|
package org.hl7.fhir.r4.conformance;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
|
|
||||||
import org.hl7.fhir.exceptions.FHIRException;
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
import org.hl7.fhir.r4.context.IWorkerContext;
|
import org.hl7.fhir.r4.context.IWorkerContext;
|
||||||
|
@ -29,7 +26,7 @@ public class ConstraintJavaGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String generate(StructureDefinition sd) throws FHIRException, IOException {
|
public String generate(StructureDefinition sd) throws FHIRException, IOException {
|
||||||
String name = Utilities.titleize(sd.getName().replace(".", "").replace("-", "").replace("\"", "")).replace(" ", "");
|
String name = sd.hasName() ? Utilities.titleize(sd.getName().replace(".", "").replace("-", "").replace("\"", "")).replace(" ", "") : "";
|
||||||
if (!Utilities.nmtokenize(name).equals(name)) {
|
if (!Utilities.nmtokenize(name).equals(name)) {
|
||||||
System.out.println("Cannot generate Java code for profile "+sd.getUrl()+" because the name \""+name+"\" is not a valid Java class name");
|
System.out.println("Cannot generate Java code for profile "+sd.getUrl()+" because the name \""+name+"\" is not a valid Java class name");
|
||||||
return null;
|
return null;
|
||||||
|
@ -46,6 +43,7 @@ public class ConstraintJavaGenerator {
|
||||||
|
|
||||||
dest.write("}\r\n");
|
dest.write("}\r\n");
|
||||||
dest.flush();
|
dest.flush();
|
||||||
|
dest.close();
|
||||||
return destFile.getAbsolutePath();
|
return destFile.getAbsolutePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package org.hl7.fhir.r4.conformance;
|
package org.hl7.fhir.r4.conformance;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -8,6 +11,9 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.hl7.fhir.exceptions.DefinitionException;
|
||||||
|
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||||
|
import org.hl7.fhir.r4.conformance.ProfileComparer.ProfileComparison;
|
||||||
import org.hl7.fhir.r4.context.IWorkerContext;
|
import org.hl7.fhir.r4.context.IWorkerContext;
|
||||||
import org.hl7.fhir.r4.formats.IParser;
|
import org.hl7.fhir.r4.formats.IParser;
|
||||||
import org.hl7.fhir.r4.model.Base;
|
import org.hl7.fhir.r4.model.Base;
|
||||||
|
@ -16,6 +22,7 @@ import org.hl7.fhir.r4.model.ElementDefinition;
|
||||||
import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionBindingComponent;
|
import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionBindingComponent;
|
||||||
import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionConstraintComponent;
|
import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionConstraintComponent;
|
||||||
import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionMappingComponent;
|
import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionMappingComponent;
|
||||||
|
import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionSlicingComponent;
|
||||||
import org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent;
|
import org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent;
|
||||||
import org.hl7.fhir.r4.model.Enumerations.BindingStrength;
|
import org.hl7.fhir.r4.model.Enumerations.BindingStrength;
|
||||||
import org.hl7.fhir.r4.model.Enumerations.PublicationStatus;
|
import org.hl7.fhir.r4.model.Enumerations.PublicationStatus;
|
||||||
|
@ -34,13 +41,15 @@ import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent;
|
||||||
import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
||||||
import org.hl7.fhir.r4.utils.DefinitionNavigator;
|
import org.hl7.fhir.r4.utils.DefinitionNavigator;
|
||||||
import org.hl7.fhir.r4.utils.ToolingExtensions;
|
import org.hl7.fhir.r4.utils.ToolingExtensions;
|
||||||
import org.hl7.fhir.exceptions.DefinitionException;
|
|
||||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
|
||||||
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||||
|
import org.hl7.fhir.utilities.TextFile;
|
||||||
import org.hl7.fhir.utilities.Utilities;
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
|
import org.hl7.fhir.utilities.Logger.LogMessageType;
|
||||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||||
import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
|
import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A engine that generates difference analysis between two sets of structure
|
* A engine that generates difference analysis between two sets of structure
|
||||||
* definitions, typically from 2 different implementation guides.
|
* definitions, typically from 2 different implementation guides.
|
||||||
|
@ -398,8 +407,11 @@ public class ProfileComparer {
|
||||||
if (isExtension(left.path()))
|
if (isExtension(left.path()))
|
||||||
return compareExtensions(outcome, path, superset, subset, left, right);
|
return compareExtensions(outcome, path, superset, subset, left, right);
|
||||||
// return true;
|
// return true;
|
||||||
else
|
else {
|
||||||
|
ElementDefinitionSlicingComponent slicingL = left.current().getSlicing();
|
||||||
|
ElementDefinitionSlicingComponent slicingR = right.current().getSlicing();
|
||||||
throw new DefinitionException("Slicing is not handled yet");
|
throw new DefinitionException("Slicing is not handled yet");
|
||||||
|
}
|
||||||
// todo: name
|
// todo: name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,8 +641,8 @@ public class ProfileComparer {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
subBinding.setValueSet(new Reference().setReference("#"+addValueSet(cvs)));
|
subBinding.setValueSet("#"+addValueSet(cvs));
|
||||||
superBinding.setValueSet(new Reference().setReference("#"+addValueSet(unite(superset, outcome, path, lvs, rvs))));
|
superBinding.setValueSet("#"+addValueSet(unite(superset, outcome, path, lvs, rvs)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -649,11 +661,11 @@ public class ProfileComparer {
|
||||||
ValueSet lvs = resolveVS(outcome.left, left.getValueSet());
|
ValueSet lvs = resolveVS(outcome.left, left.getValueSet());
|
||||||
ValueSet rvs = resolveVS(outcome.left, right.getValueSet());
|
ValueSet rvs = resolveVS(outcome.left, right.getValueSet());
|
||||||
if (lvs != null && rvs != null)
|
if (lvs != null && rvs != null)
|
||||||
union.setValueSet(new Reference().setReference("#"+addValueSet(unite(ed, outcome, path, lvs, rvs))));
|
union.setValueSet("#"+addValueSet(unite(ed, outcome, path, lvs, rvs)));
|
||||||
else if (lvs != null)
|
else if (lvs != null)
|
||||||
union.setValueSet(new Reference().setReference("#"+addValueSet(lvs)));
|
union.setValueSet("#"+addValueSet(lvs));
|
||||||
else if (rvs != null)
|
else if (rvs != null)
|
||||||
union.setValueSet(new Reference().setReference("#"+addValueSet(rvs)));
|
union.setValueSet("#"+addValueSet(rvs));
|
||||||
}
|
}
|
||||||
return union;
|
return union;
|
||||||
}
|
}
|
||||||
|
@ -710,17 +722,10 @@ public class ProfileComparer {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ValueSet resolveVS(StructureDefinition ctxtLeft, Type vsRef) {
|
private ValueSet resolveVS(StructureDefinition ctxtLeft, String vsRef) {
|
||||||
if (vsRef == null)
|
if (vsRef == null)
|
||||||
return null;
|
return null;
|
||||||
if (vsRef instanceof UriType)
|
return context.fetchResource(ValueSet.class, vsRef);
|
||||||
return null;
|
|
||||||
else {
|
|
||||||
Reference ref = (Reference) vsRef;
|
|
||||||
if (!ref.hasReference())
|
|
||||||
return null;
|
|
||||||
return context.fetchResource(ValueSet.class, ref.getReference());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ValueSet intersectByDefinition(ValueSet lvs, ValueSet rvs) {
|
private ValueSet intersectByDefinition(ValueSet lvs, ValueSet rvs) {
|
||||||
|
@ -1166,6 +1171,100 @@ public class ProfileComparer {
|
||||||
this.rightName = rightName;
|
this.rightName = rightName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String genPCLink(String leftName, String leftLink) {
|
||||||
|
return "<a href=\""+leftLink+"\">"+Utilities.escapeXml(leftName)+"</a>";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String genPCTable() {
|
||||||
|
StringBuilder b = new StringBuilder();
|
||||||
|
|
||||||
|
b.append("<table class=\"grid\">\r\n");
|
||||||
|
b.append("<tr>");
|
||||||
|
b.append(" <td><b>Left</b></td>");
|
||||||
|
b.append(" <td><b>Right</b></td>");
|
||||||
|
b.append(" <td><b>Comparison</b></td>");
|
||||||
|
b.append(" <td><b>Error #</b></td>");
|
||||||
|
b.append(" <td><b>Warning #</b></td>");
|
||||||
|
b.append(" <td><b>Hint #</b></td>");
|
||||||
|
b.append("</tr>");
|
||||||
|
|
||||||
|
for (ProfileComparison cmp : getComparisons()) {
|
||||||
|
b.append("<tr>");
|
||||||
|
b.append(" <td><a href=\""+cmp.getLeft().getUserString("path")+"\">"+Utilities.escapeXml(cmp.getLeft().getName())+"</a></td>");
|
||||||
|
b.append(" <td><a href=\""+cmp.getRight().getUserString("path")+"\">"+Utilities.escapeXml(cmp.getRight().getName())+"</a></td>");
|
||||||
|
b.append(" <td><a href=\""+getId()+"."+cmp.getId()+".html\">Click Here</a></td>");
|
||||||
|
b.append(" <td>"+cmp.getErrorCount()+"</td>");
|
||||||
|
b.append(" <td>"+cmp.getWarningCount()+"</td>");
|
||||||
|
b.append(" <td>"+cmp.getHintCount()+"</td>");
|
||||||
|
b.append("</tr>");
|
||||||
|
}
|
||||||
|
b.append("</table>\r\n");
|
||||||
|
|
||||||
|
return b.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String generate(String dest) throws IOException {
|
||||||
|
// ok, all compared; now produce the output
|
||||||
|
// first page we produce is simply the index
|
||||||
|
Map<String, String> vars = new HashMap<String, String>();
|
||||||
|
vars.put("title", getTitle());
|
||||||
|
vars.put("left", genPCLink(getLeftName(), getLeftLink()));
|
||||||
|
vars.put("right", genPCLink(getRightName(), getRightLink()));
|
||||||
|
vars.put("table", genPCTable());
|
||||||
|
producePage(summaryTemplate(), Utilities.path(dest, getId()+".html"), vars);
|
||||||
|
|
||||||
|
// page.log(" ... generate", LogMessageType.Process);
|
||||||
|
// String src = TextFile.fileToString(page.getFolders().srcDir + "template-comparison-set.html");
|
||||||
|
// src = page.processPageIncludes(n+".html", src, "?type", null, "??path", null, null, "Comparison", pc, null, null, page.getDefinitions().getWorkgroups().get("fhir"));
|
||||||
|
// TextFile.stringToFile(src, Utilities.path(page.getFolders().dstDir, n+".html"));
|
||||||
|
// cachePage(n + ".html", src, "Comparison "+pc.getTitle(), false);
|
||||||
|
//
|
||||||
|
// // then we produce a comparison page for each pair
|
||||||
|
// for (ProfileComparison cmp : pc.getComparisons()) {
|
||||||
|
// src = TextFile.fileToString(page.getFolders().srcDir + "template-comparison.html");
|
||||||
|
// src = page.processPageIncludes(n+"."+cmp.getId()+".html", src, "?type", null, "??path", null, null, "Comparison", cmp, null, null, page.getDefinitions().getWorkgroups().get("fhir"));
|
||||||
|
// TextFile.stringToFile(src, Utilities.path(page.getFolders().dstDir, n+"."+cmp.getId()+".html"));
|
||||||
|
// cachePage(n +"."+cmp.getId()+".html", src, "Comparison "+pc.getTitle(), false);
|
||||||
|
// }
|
||||||
|
// // and also individual pages for each pair outcome
|
||||||
|
// // then we produce value set pages for each value set
|
||||||
|
//
|
||||||
|
// // TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void producePage(String src, String path, Map<String, String> vars) throws IOException {
|
||||||
|
while (src.contains("[%"))
|
||||||
|
{
|
||||||
|
int i1 = src.indexOf("[%");
|
||||||
|
int i2 = src.substring(i1).indexOf("%]")+i1;
|
||||||
|
String s1 = src.substring(0, i1);
|
||||||
|
String s2 = src.substring(i1 + 2, i2).trim();
|
||||||
|
String s3 = src.substring(i2+2);
|
||||||
|
String v = vars.containsKey(s2) ? vars.get(s2) : "???";
|
||||||
|
src = s1+v+s3;
|
||||||
|
}
|
||||||
|
TextFile.stringToFile(src, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String summaryTemplate() throws IOException {
|
||||||
|
return cachedFetch("04a9d69a-47f2-4250-8645-bf5d880a8eaa-1.fhir-template", "http://build.fhir.org/template-comparison-set.html.template");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String cachedFetch(String id, String source) throws IOException {
|
||||||
|
String tmpDir = System.getProperty("java.io.tmpdir");
|
||||||
|
String local = Utilities.path(tmpDir, id);
|
||||||
|
File f = new File(local);
|
||||||
|
if (f.exists())
|
||||||
|
return TextFile.fileToString(f);
|
||||||
|
URL url = new URL(source);
|
||||||
|
URLConnection c = url.openConnection();
|
||||||
|
String result = TextFile.streamToString(c.getInputStream());
|
||||||
|
TextFile.stringToFile(result, f);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,6 +11,7 @@ import java.util.List;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
import org.hl7.fhir.r4.context.IWorkerContext;
|
import org.hl7.fhir.r4.context.IWorkerContext;
|
||||||
import org.hl7.fhir.r4.elementmodel.TurtleParser;
|
import org.hl7.fhir.r4.elementmodel.TurtleParser;
|
||||||
import org.hl7.fhir.r4.model.DomainResource;
|
import org.hl7.fhir.r4.model.DomainResource;
|
||||||
|
@ -24,7 +25,6 @@ import org.hl7.fhir.r4.model.UriType;
|
||||||
import org.hl7.fhir.r4.model.ValueSet;
|
import org.hl7.fhir.r4.model.ValueSet;
|
||||||
import org.hl7.fhir.r4.terminologies.ValueSetExpander;
|
import org.hl7.fhir.r4.terminologies.ValueSetExpander;
|
||||||
import org.hl7.fhir.r4.utils.ToolingExtensions;
|
import org.hl7.fhir.r4.utils.ToolingExtensions;
|
||||||
import org.hl7.fhir.exceptions.FHIRException;
|
|
||||||
import org.stringtemplate.v4.ST;
|
import org.stringtemplate.v4.ST;
|
||||||
|
|
||||||
public class ShExGenerator {
|
public class ShExGenerator {
|
||||||
|
@ -388,7 +388,7 @@ public class ShExGenerator {
|
||||||
for (String dt : new HashSet<String>(datatypes)) {
|
for (String dt : new HashSet<String>(datatypes)) {
|
||||||
if (!emittedDatatypes.contains(dt)) {
|
if (!emittedDatatypes.contains(dt)) {
|
||||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class,
|
StructureDefinition sd = context.fetchResource(StructureDefinition.class,
|
||||||
ProfileUtilities.sdNs(dt));
|
ProfileUtilities.sdNs(dt, null));
|
||||||
// TODO: Figure out why the line below doesn't work
|
// TODO: Figure out why the line below doesn't work
|
||||||
// if (sd != null && !uniq_structures.contains(sd))
|
// if (sd != null && !uniq_structures.contains(sd))
|
||||||
if(sd != null && !uniq_structure_urls.contains(sd.getUrl()))
|
if(sd != null && !uniq_structure_urls.contains(sd.getUrl()))
|
||||||
|
@ -748,23 +748,11 @@ public class ShExGenerator {
|
||||||
|
|
||||||
|
|
||||||
// TODO: find a utility that implements this
|
// TODO: find a utility that implements this
|
||||||
private ValueSet resolveBindingReference(DomainResource ctxt, Type reference) {
|
private ValueSet resolveBindingReference(DomainResource ctxt, String reference) {
|
||||||
if (reference instanceof UriType) {
|
try {
|
||||||
return context.fetchResource(ValueSet.class, ((UriType) reference).getValue().toString());
|
return context.fetchResource(ValueSet.class, reference);
|
||||||
}
|
} catch (Throwable e) {
|
||||||
else if (reference instanceof Reference) {
|
|
||||||
String s = ((Reference) reference).getReference();
|
|
||||||
if (s.startsWith("#")) {
|
|
||||||
for (Resource c : ctxt.getContained()) {
|
|
||||||
if (c.getId().equals(s.substring(1)) && (c instanceof ValueSet))
|
|
||||||
return (ValueSet) c;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return context.fetchResource(ValueSet.class, ((Reference) reference).getReference());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,520 @@
|
||||||
|
package org.hl7.fhir.r4.conformance;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
/*
|
||||||
|
Copyright (c) 2011+, HL7, Inc
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of HL7 nor the names of its contributors may be used to
|
||||||
|
endorse or promote products derived from this software without specific
|
||||||
|
prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||||
|
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
|
import org.hl7.fhir.r4.context.IWorkerContext;
|
||||||
|
import org.hl7.fhir.r4.model.ElementDefinition;
|
||||||
|
import org.hl7.fhir.r4.model.ElementDefinition.PropertyRepresentation;
|
||||||
|
import org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent;
|
||||||
|
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||||
|
import org.hl7.fhir.r4.utils.ToolingExtensions;
|
||||||
|
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||||
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
|
|
||||||
|
|
||||||
|
public class XmlSchemaGenerator {
|
||||||
|
|
||||||
|
public class QName {
|
||||||
|
|
||||||
|
public String type;
|
||||||
|
public String typeNs;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return typeNs+":"+type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ElementToGenerate {
|
||||||
|
|
||||||
|
private String tname;
|
||||||
|
private StructureDefinition sd;
|
||||||
|
private ElementDefinition ed;
|
||||||
|
|
||||||
|
public ElementToGenerate(String tname, StructureDefinition sd, ElementDefinition edc) {
|
||||||
|
this.tname = tname;
|
||||||
|
this.sd = sd;
|
||||||
|
this.ed = edc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String folder;
|
||||||
|
private IWorkerContext context;
|
||||||
|
private boolean single;
|
||||||
|
private String version;
|
||||||
|
private String genDate;
|
||||||
|
private String license;
|
||||||
|
private boolean annotations;
|
||||||
|
|
||||||
|
public XmlSchemaGenerator(String folder, IWorkerContext context) {
|
||||||
|
this.folder = folder;
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSingle() {
|
||||||
|
return single;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSingle(boolean single) {
|
||||||
|
this.single = single;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVersion(String version) {
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGenDate() {
|
||||||
|
return genDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGenDate(String genDate) {
|
||||||
|
this.genDate = genDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLicense() {
|
||||||
|
return license;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLicense(String license) {
|
||||||
|
this.license = license;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean isAnnotations() {
|
||||||
|
return annotations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAnnotations(boolean annotations) {
|
||||||
|
this.annotations = annotations;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Set<ElementDefinition> processed = new HashSet<ElementDefinition>();
|
||||||
|
private Set<StructureDefinition> processedLibs = new HashSet<StructureDefinition>();
|
||||||
|
private Set<String> typeNames = new HashSet<String>();
|
||||||
|
private OutputStreamWriter writer;
|
||||||
|
private Map<String, String> namespaces = new HashMap<String, String>();
|
||||||
|
private Queue<ElementToGenerate> queue = new LinkedList<ElementToGenerate>();
|
||||||
|
private Queue<StructureDefinition> queueLib = new LinkedList<StructureDefinition>();
|
||||||
|
private Map<String, StructureDefinition> library;
|
||||||
|
private boolean useNarrative;
|
||||||
|
|
||||||
|
private void w(String s) throws IOException {
|
||||||
|
writer.write(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ln(String s) throws IOException {
|
||||||
|
writer.write(s);
|
||||||
|
writer.write("\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void close() throws IOException {
|
||||||
|
if (writer != null) {
|
||||||
|
ln("</xs:schema>");
|
||||||
|
writer.flush();
|
||||||
|
writer.close();
|
||||||
|
writer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String start(StructureDefinition sd, String ns) throws IOException, FHIRException {
|
||||||
|
String lang = "en";
|
||||||
|
if (sd.hasLanguage())
|
||||||
|
lang = sd.getLanguage();
|
||||||
|
|
||||||
|
if (single && writer != null) {
|
||||||
|
if (!ns.equals(getNs(sd)))
|
||||||
|
throw new FHIRException("namespace inconsistency: "+ns+" vs "+getNs(sd));
|
||||||
|
return lang;
|
||||||
|
}
|
||||||
|
close();
|
||||||
|
|
||||||
|
writer = new OutputStreamWriter(new FileOutputStream(Utilities.path(folder, tail(sd.getType()+".xsd"))), "UTF-8");
|
||||||
|
ln("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||||
|
ln("<!-- ");
|
||||||
|
ln(license);
|
||||||
|
ln("");
|
||||||
|
ln(" Generated on "+genDate+" for FHIR v"+version+" ");
|
||||||
|
ln("");
|
||||||
|
ln(" Note: this schema does not contain all the knowledge represented in the underlying content model");
|
||||||
|
ln("");
|
||||||
|
ln("-->");
|
||||||
|
ln("<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:fhir=\"http://hl7.org/fhir\" xmlns:xhtml=\"http://www.w3.org/1999/xhtml\" "+
|
||||||
|
"xmlns:lm=\""+ns+"\" targetNamespace=\""+ns+"\" elementFormDefault=\"qualified\" version=\"1.0\">");
|
||||||
|
ln(" <xs:import schemaLocation=\"fhir-common.xsd\" namespace=\"http://hl7.org/fhir\"/>");
|
||||||
|
if (useNarrative) {
|
||||||
|
if (ns.equals("urn:hl7-org:v3"))
|
||||||
|
ln(" <xs:include schemaLocation=\"cda-narrative.xsd\"/>");
|
||||||
|
else
|
||||||
|
ln(" <xs:import schemaLocation=\"cda-narrative.xsd\" namespace=\"urn:hl7-org:v3\"/>");
|
||||||
|
}
|
||||||
|
namespaces.clear();
|
||||||
|
namespaces.put(ns, "lm");
|
||||||
|
namespaces.put("http://hl7.org/fhir", "fhir");
|
||||||
|
typeNames.clear();
|
||||||
|
|
||||||
|
return lang;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String getNs(StructureDefinition sd) {
|
||||||
|
String ns = "http://hl7.org/fhir";
|
||||||
|
if (sd.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace"))
|
||||||
|
ns = ToolingExtensions.readStringExtension(sd, "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace");
|
||||||
|
return ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generate(StructureDefinition entry, Map<String, StructureDefinition> library) throws Exception {
|
||||||
|
processedLibs.clear();
|
||||||
|
|
||||||
|
this.library = library;
|
||||||
|
checkLib(entry);
|
||||||
|
|
||||||
|
String ns = getNs(entry);
|
||||||
|
String lang = start(entry, ns);
|
||||||
|
|
||||||
|
w(" <xs:element name=\""+tail(entry.getType())+"\" type=\"lm:"+tail(entry.getType())+"\"");
|
||||||
|
if (annotations) {
|
||||||
|
ln(">");
|
||||||
|
ln(" <xs:annotation>");
|
||||||
|
ln(" <xs:documentation xml:lang=\""+lang+"\">"+Utilities.escapeXml(entry.getDescription())+"</xs:documentation>");
|
||||||
|
ln(" </xs:annotation>");
|
||||||
|
ln(" </xs:element>");
|
||||||
|
} else
|
||||||
|
ln("/>");
|
||||||
|
|
||||||
|
produceType(entry, entry.getSnapshot().getElement().get(0), tail(entry.getType()), getQN(entry, entry.getBaseDefinition()), lang);
|
||||||
|
while (!queue.isEmpty()) {
|
||||||
|
ElementToGenerate q = queue.poll();
|
||||||
|
produceType(q.sd, q.ed, q.tname, getQN(q.sd, q.ed, "http://hl7.org/fhir/StructureDefinition/Element", false), lang);
|
||||||
|
}
|
||||||
|
while (!queueLib.isEmpty()) {
|
||||||
|
generateInner(queueLib.poll());
|
||||||
|
}
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void checkLib(StructureDefinition entry) {
|
||||||
|
for (ElementDefinition ed : entry.getSnapshot().getElement()) {
|
||||||
|
if (ed.hasRepresentation(PropertyRepresentation.CDATEXT)) {
|
||||||
|
useNarrative = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (StructureDefinition sd : library.values()) {
|
||||||
|
for (ElementDefinition ed : sd.getSnapshot().getElement()) {
|
||||||
|
if (ed.hasRepresentation(PropertyRepresentation.CDATEXT)) {
|
||||||
|
useNarrative = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateInner(StructureDefinition sd) throws IOException, FHIRException {
|
||||||
|
if (processedLibs.contains(sd))
|
||||||
|
return;
|
||||||
|
processedLibs.add(sd);
|
||||||
|
|
||||||
|
String ns = getNs(sd);
|
||||||
|
String lang = start(sd, ns);
|
||||||
|
|
||||||
|
if (sd.getSnapshot().getElement().isEmpty())
|
||||||
|
throw new FHIRException("no snap shot on "+sd.getUrl());
|
||||||
|
|
||||||
|
produceType(sd, sd.getSnapshot().getElement().get(0), tail(sd.getType()), getQN(sd, sd.getBaseDefinition()), lang);
|
||||||
|
while (!queue.isEmpty()) {
|
||||||
|
ElementToGenerate q = queue.poll();
|
||||||
|
produceType(q.sd, q.ed, q.tname, getQN(q.sd, q.ed, "http://hl7.org/fhir/StructureDefinition/Element", false), lang);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String tail(String url) {
|
||||||
|
return url.contains("/") ? url.substring(url.lastIndexOf("/")+1) : url;
|
||||||
|
}
|
||||||
|
private String root(String url) {
|
||||||
|
return url.contains("/") ? url.substring(0, url.lastIndexOf("/")) : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String tailDot(String url) {
|
||||||
|
return url.contains(".") ? url.substring(url.lastIndexOf(".")+1) : url;
|
||||||
|
}
|
||||||
|
private void produceType(StructureDefinition sd, ElementDefinition ed, String typeName, QName typeParent, String lang) throws IOException, FHIRException {
|
||||||
|
if (processed.contains(ed))
|
||||||
|
return;
|
||||||
|
processed.add(ed);
|
||||||
|
|
||||||
|
// ok
|
||||||
|
ln(" <xs:complexType name=\""+typeName+"\">");
|
||||||
|
if (annotations) {
|
||||||
|
ln(" <xs:annotation>");
|
||||||
|
ln(" <xs:documentation xml:lang=\""+lang+"\">"+Utilities.escapeXml(ed.getDefinition())+"</xs:documentation>");
|
||||||
|
ln(" </xs:annotation>");
|
||||||
|
}
|
||||||
|
ln(" <xs:complexContent>");
|
||||||
|
ln(" <xs:extension base=\""+typeParent.toString()+"\">");
|
||||||
|
ln(" <xs:sequence>");
|
||||||
|
|
||||||
|
// hack....
|
||||||
|
for (ElementDefinition edc : ProfileUtilities.getChildList(sd, ed)) {
|
||||||
|
if (!(edc.hasRepresentation(PropertyRepresentation.XMLATTR) || edc.hasRepresentation(PropertyRepresentation.XMLTEXT)) && !inheritedElement(edc))
|
||||||
|
produceElement(sd, ed, edc, lang);
|
||||||
|
}
|
||||||
|
ln(" </xs:sequence>");
|
||||||
|
for (ElementDefinition edc : ProfileUtilities.getChildList(sd, ed)) {
|
||||||
|
if ((edc.hasRepresentation(PropertyRepresentation.XMLATTR) || edc.hasRepresentation(PropertyRepresentation.XMLTEXT)) && !inheritedElement(edc))
|
||||||
|
produceAttribute(sd, ed, edc, lang);
|
||||||
|
}
|
||||||
|
ln(" </xs:extension>");
|
||||||
|
ln(" </xs:complexContent>");
|
||||||
|
ln(" </xs:complexType>");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean inheritedElement(ElementDefinition edc) {
|
||||||
|
return !edc.getPath().equals(edc.getBase().getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void produceElement(StructureDefinition sd, ElementDefinition ed, ElementDefinition edc, String lang) throws IOException, FHIRException {
|
||||||
|
if (edc.getType().size() == 0)
|
||||||
|
throw new Error("No type at "+edc.getPath());
|
||||||
|
|
||||||
|
if (edc.getType().size() > 1 && edc.hasRepresentation(PropertyRepresentation.TYPEATTR)) {
|
||||||
|
// first, find the common base type
|
||||||
|
StructureDefinition lib = getCommonAncestor(edc.getType());
|
||||||
|
if (lib == null)
|
||||||
|
throw new Error("Common ancester not found at "+edc.getPath());
|
||||||
|
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
|
||||||
|
for (TypeRefComponent t : edc.getType()) {
|
||||||
|
b.append(getQN(sd, edc, t.getCode(), true).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
String name = tailDot(edc.getPath());
|
||||||
|
String min = String.valueOf(edc.getMin());
|
||||||
|
String max = edc.getMax();
|
||||||
|
if ("*".equals(max))
|
||||||
|
max = "unbounded";
|
||||||
|
|
||||||
|
QName qn = getQN(sd, edc, lib.getUrl(), true);
|
||||||
|
|
||||||
|
ln(" <xs:element name=\""+name+"\" minOccurs=\""+min+"\" maxOccurs=\""+max+"\" type=\""+qn.typeNs+":"+qn.type+"\">");
|
||||||
|
ln(" <xs:annotation>");
|
||||||
|
ln(" <xs:appinfo xml:lang=\"en\">Possible types: "+b.toString()+"</xs:appinfo>");
|
||||||
|
if (annotations && edc.hasDefinition())
|
||||||
|
ln(" <xs:documentation xml:lang=\""+lang+"\">"+Utilities.escapeXml(edc.getDefinition())+"</xs:documentation>");
|
||||||
|
ln(" </xs:annotation>");
|
||||||
|
ln(" </xs:element>");
|
||||||
|
} else for (TypeRefComponent t : edc.getType()) {
|
||||||
|
String name = tailDot(edc.getPath());
|
||||||
|
if (edc.getType().size() > 1)
|
||||||
|
name = name + Utilities.capitalize(t.getCode());
|
||||||
|
QName qn = getQN(sd, edc, t.getCode(), true);
|
||||||
|
String min = String.valueOf(edc.getMin());
|
||||||
|
String max = edc.getMax();
|
||||||
|
if ("*".equals(max))
|
||||||
|
max = "unbounded";
|
||||||
|
|
||||||
|
|
||||||
|
w(" <xs:element name=\""+name+"\" minOccurs=\""+min+"\" maxOccurs=\""+max+"\" type=\""+qn.typeNs+":"+qn.type+"\"");
|
||||||
|
if (annotations && edc.hasDefinition()) {
|
||||||
|
ln(">");
|
||||||
|
ln(" <xs:annotation>");
|
||||||
|
ln(" <xs:documentation xml:lang=\""+lang+"\">"+Utilities.escapeXml(edc.getDefinition())+"</xs:documentation>");
|
||||||
|
ln(" </xs:annotation>");
|
||||||
|
ln(" </xs:element>");
|
||||||
|
} else
|
||||||
|
ln("/>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public QName getQN(StructureDefinition sd, String type) throws FHIRException {
|
||||||
|
return getQN(sd, sd.getSnapshot().getElementFirstRep(), type, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public QName getQN(StructureDefinition sd, ElementDefinition edc, String t, boolean chase) throws FHIRException {
|
||||||
|
QName qn = new QName();
|
||||||
|
qn.type = Utilities.isAbsoluteUrl(t) ? tail(t) : t;
|
||||||
|
if (Utilities.isAbsoluteUrl(t)) {
|
||||||
|
String ns = root(t);
|
||||||
|
if (ns.equals(root(sd.getUrl())))
|
||||||
|
ns = getNs(sd);
|
||||||
|
if (ns.equals("http://hl7.org/fhir/StructureDefinition"))
|
||||||
|
ns = "http://hl7.org/fhir";
|
||||||
|
if (!namespaces.containsKey(ns))
|
||||||
|
throw new FHIRException("Unknown type namespace "+ns+" for "+edc.getPath());
|
||||||
|
qn.typeNs = namespaces.get(ns);
|
||||||
|
StructureDefinition lib = library.get(t);
|
||||||
|
if (lib == null && !Utilities.existsInList(t, "http://hl7.org/fhir/cda/StructureDefinition/StrucDoc.Text", "http://hl7.org/fhir/StructureDefinition/Element"))
|
||||||
|
throw new FHIRException("Unable to resolve "+t+" for "+edc.getPath());
|
||||||
|
if (lib != null)
|
||||||
|
queueLib.add(lib);
|
||||||
|
} else
|
||||||
|
qn.typeNs = namespaces.get("http://hl7.org/fhir");
|
||||||
|
|
||||||
|
if (chase && qn.type.equals("Element")) {
|
||||||
|
String tname = typeNameFromPath(edc);
|
||||||
|
if (typeNames.contains(tname)) {
|
||||||
|
int i = 1;
|
||||||
|
while (typeNames.contains(tname+i))
|
||||||
|
i++;
|
||||||
|
tname = tname+i;
|
||||||
|
}
|
||||||
|
queue.add(new ElementToGenerate(tname, sd, edc));
|
||||||
|
qn.typeNs = "lm";
|
||||||
|
qn.type = tname;
|
||||||
|
}
|
||||||
|
return qn;
|
||||||
|
}
|
||||||
|
|
||||||
|
private StructureDefinition getCommonAncestor(List<TypeRefComponent> type) throws FHIRException {
|
||||||
|
StructureDefinition sd = library.get(type.get(0).getCode());
|
||||||
|
if (sd == null)
|
||||||
|
throw new FHIRException("Unable to find definition for "+type.get(0).getCode());
|
||||||
|
for (int i = 1; i < type.size(); i++) {
|
||||||
|
StructureDefinition t = library.get(type.get(i).getCode());
|
||||||
|
if (t == null)
|
||||||
|
throw new FHIRException("Unable to find definition for "+type.get(i).getCode());
|
||||||
|
sd = getCommonAncestor(sd, t);
|
||||||
|
}
|
||||||
|
return sd;
|
||||||
|
}
|
||||||
|
|
||||||
|
private StructureDefinition getCommonAncestor(StructureDefinition sd1, StructureDefinition sd2) throws FHIRException {
|
||||||
|
// this will always return something because everything comes from Element
|
||||||
|
List<StructureDefinition> chain1 = new ArrayList<>();
|
||||||
|
List<StructureDefinition> chain2 = new ArrayList<>();
|
||||||
|
chain1.add(sd1);
|
||||||
|
chain2.add(sd2);
|
||||||
|
StructureDefinition root = library.get("Element");
|
||||||
|
StructureDefinition common = findIntersection(chain1, chain2);
|
||||||
|
boolean chain1Done = false;
|
||||||
|
boolean chain2Done = false;
|
||||||
|
while (common == null) {
|
||||||
|
chain1Done = checkChain(chain1, root, chain1Done);
|
||||||
|
chain2Done = checkChain(chain2, root, chain2Done);
|
||||||
|
if (chain1Done && chain2Done)
|
||||||
|
return null;
|
||||||
|
common = findIntersection(chain1, chain2);
|
||||||
|
}
|
||||||
|
return common;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private StructureDefinition findIntersection(List<StructureDefinition> chain1, List<StructureDefinition> chain2) {
|
||||||
|
for (StructureDefinition sd1 : chain1)
|
||||||
|
for (StructureDefinition sd2 : chain2)
|
||||||
|
if (sd1 == sd2)
|
||||||
|
return sd1;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkChain(List<StructureDefinition> chain1, StructureDefinition root, boolean chain1Done) throws FHIRException {
|
||||||
|
if (!chain1Done) {
|
||||||
|
StructureDefinition sd = chain1.get(chain1.size()-1);
|
||||||
|
String bu = sd.getBaseDefinition();
|
||||||
|
if (bu == null)
|
||||||
|
throw new FHIRException("No base definition for "+sd.getUrl());
|
||||||
|
StructureDefinition t = library.get(bu);
|
||||||
|
if (t == null)
|
||||||
|
chain1Done = true;
|
||||||
|
else
|
||||||
|
chain1.add(t);
|
||||||
|
}
|
||||||
|
return chain1Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
private StructureDefinition getBase(StructureDefinition structureDefinition) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String typeNameFromPath(ElementDefinition edc) {
|
||||||
|
StringBuilder b = new StringBuilder();
|
||||||
|
boolean up = true;
|
||||||
|
for (char ch : edc.getPath().toCharArray()) {
|
||||||
|
if (ch == '.')
|
||||||
|
up = true;
|
||||||
|
else if (up) {
|
||||||
|
b.append(Character.toUpperCase(ch));
|
||||||
|
up = false;
|
||||||
|
} else
|
||||||
|
b.append(ch);
|
||||||
|
}
|
||||||
|
return b.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void produceAttribute(StructureDefinition sd, ElementDefinition ed, ElementDefinition edc, String lang) throws IOException, FHIRException {
|
||||||
|
TypeRefComponent t = edc.getTypeFirstRep();
|
||||||
|
String name = tailDot(edc.getPath());
|
||||||
|
String min = String.valueOf(edc.getMin());
|
||||||
|
String max = edc.getMax();
|
||||||
|
// todo: check it's a code...
|
||||||
|
// if (!max.equals("1"))
|
||||||
|
// throw new FHIRException("Illegal cardinality \""+max+"\" for attribute "+edc.getPath());
|
||||||
|
|
||||||
|
if (Utilities.isAbsoluteUrl(t.getCode()))
|
||||||
|
throw new FHIRException("Only FHIR primitive types are supported for attributes ("+t.getCode()+")");
|
||||||
|
String typeNs = namespaces.get("http://hl7.org/fhir");
|
||||||
|
String type = t.getCode();
|
||||||
|
|
||||||
|
w(" <xs:attribute name=\""+name+"\" use=\""+(min.equals("0") || edc.hasFixed() || edc.hasDefaultValue() ? "optional" : "required")+"\" type=\""+typeNs+":"+type+(typeNs.equals("fhir") ? "-primitive" : "")+"\""+
|
||||||
|
(edc.hasFixed() ? " fixed=\""+edc.getFixed().primitiveValue()+"\"" : "")+(edc.hasDefaultValue() && !edc.hasFixed() ? " default=\""+edc.getDefaultValue().primitiveValue()+"\"" : "")+"");
|
||||||
|
if (annotations && edc.hasDefinition()) {
|
||||||
|
ln(">");
|
||||||
|
ln(" <xs:annotation>");
|
||||||
|
ln(" <xs:documentation xml:lang=\""+lang+"\">"+Utilities.escapeXml(edc.getDefinition())+"</xs:documentation>");
|
||||||
|
ln(" </xs:annotation>");
|
||||||
|
ln(" </xs:attribute>");
|
||||||
|
} else
|
||||||
|
ln("/>");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -11,8 +11,8 @@ import org.hl7.fhir.r4.model.CodeableConcept;
|
||||||
import org.hl7.fhir.r4.model.Coding;
|
import org.hl7.fhir.r4.model.Coding;
|
||||||
import org.hl7.fhir.r4.model.ConceptMap;
|
import org.hl7.fhir.r4.model.ConceptMap;
|
||||||
import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionBindingComponent;
|
import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionBindingComponent;
|
||||||
import org.hl7.fhir.r4.model.ExpansionProfile;
|
|
||||||
import org.hl7.fhir.r4.model.MetadataResource;
|
import org.hl7.fhir.r4.model.MetadataResource;
|
||||||
|
import org.hl7.fhir.r4.model.Parameters;
|
||||||
import org.hl7.fhir.r4.model.Resource;
|
import org.hl7.fhir.r4.model.Resource;
|
||||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||||
import org.hl7.fhir.r4.model.StructureMap;
|
import org.hl7.fhir.r4.model.StructureMap;
|
||||||
|
@ -194,8 +194,8 @@ public interface IWorkerContext {
|
||||||
|
|
||||||
// -- Terminology services ------------------------------------------------------
|
// -- Terminology services ------------------------------------------------------
|
||||||
|
|
||||||
public ExpansionProfile getExpansionProfile();
|
public Parameters getExpansionParameters();
|
||||||
public void setExpansionProfile(ExpansionProfile expProfile);
|
public void setExpansionProfile(Parameters expParameters);
|
||||||
|
|
||||||
// these are the terminology services used internally by the tools
|
// these are the terminology services used internally by the tools
|
||||||
/**
|
/**
|
||||||
|
@ -256,7 +256,7 @@ public interface IWorkerContext {
|
||||||
* @return
|
* @return
|
||||||
* @throws FHIRException
|
* @throws FHIRException
|
||||||
*/
|
*/
|
||||||
public ValueSetExpansionComponent expandVS(ConceptSetComponent inc, boolean heirarchical) throws TerminologyServiceException;
|
public ValueSetExpansionOutcome expandVS(ConceptSetComponent inc, boolean heirarchical) throws TerminologyServiceException;
|
||||||
|
|
||||||
public class ValidationResult {
|
public class ValidationResult {
|
||||||
private ConceptDefinitionComponent definition;
|
private ConceptDefinitionComponent definition;
|
||||||
|
@ -286,7 +286,7 @@ public interface IWorkerContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOk() {
|
public boolean isOk() {
|
||||||
return definition != null;
|
return severity == null || severity == IssueSeverity.INFORMATION || severity == IssueSeverity.WARNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDisplay() {
|
public String getDisplay() {
|
||||||
|
@ -314,6 +314,16 @@ public interface IWorkerContext {
|
||||||
public TerminologyServiceErrorClass getErrorClass() {
|
public TerminologyServiceErrorClass getErrorClass() {
|
||||||
return errorClass;
|
return errorClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ValidationResult setSeverity(IssueSeverity severity) {
|
||||||
|
this.severity = severity;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValidationResult setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -348,6 +358,7 @@ public interface IWorkerContext {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public ValidationResult validateCode(String system, String code, String display, ValueSet vs);
|
public ValidationResult validateCode(String system, String code, String display, ValueSet vs);
|
||||||
|
public ValidationResult validateCode(String code, ValueSet vs);
|
||||||
public ValidationResult validateCode(Coding code, ValueSet vs);
|
public ValidationResult validateCode(Coding code, ValueSet vs);
|
||||||
public ValidationResult validateCode(CodeableConcept code, ValueSet vs);
|
public ValidationResult validateCode(CodeableConcept code, ValueSet vs);
|
||||||
|
|
||||||
|
@ -391,10 +402,16 @@ public interface IWorkerContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLogger(ILoggingService logger);
|
public void setLogger(ILoggingService logger);
|
||||||
|
public ILoggingService getLogger();
|
||||||
|
|
||||||
public boolean isNoTerminologyServer();
|
public boolean isNoTerminologyServer();
|
||||||
|
|
||||||
public TranslationServices translator();
|
public TranslationServices translator();
|
||||||
public List<StructureMap> listTransforms();
|
public List<StructureMap> listTransforms();
|
||||||
public StructureMap getTransform(String url);
|
public StructureMap getTransform(String url);
|
||||||
|
|
||||||
|
public String getOverrideVersionNs();
|
||||||
|
public void setOverrideVersionNs(String value);
|
||||||
|
|
||||||
|
public StructureDefinition fetchTypeDefinition(String typeName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,7 @@ import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||||
import org.hl7.fhir.utilities.CSFileInputStream;
|
import org.hl7.fhir.utilities.CSFileInputStream;
|
||||||
import org.hl7.fhir.utilities.OIDUtils;
|
import org.hl7.fhir.utilities.OIDUtils;
|
||||||
import org.hl7.fhir.utilities.Utilities;
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
|
import org.hl7.fhir.utilities.cache.NpmPackage;
|
||||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
||||||
import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
|
import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
|
||||||
|
@ -92,12 +93,13 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
|
||||||
private String date;
|
private String date;
|
||||||
private IValidatorFactory validatorFactory;
|
private IValidatorFactory validatorFactory;
|
||||||
private UcumService ucumService;
|
private UcumService ucumService;
|
||||||
|
private boolean ignoreProfileErrors;
|
||||||
|
|
||||||
public SimpleWorkerContext() {
|
public SimpleWorkerContext() throws FileNotFoundException, IOException, FHIRException {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SimpleWorkerContext(SimpleWorkerContext other) {
|
public SimpleWorkerContext(SimpleWorkerContext other) throws FileNotFoundException, IOException, FHIRException {
|
||||||
super();
|
super();
|
||||||
copy(other);
|
copy(other);
|
||||||
}
|
}
|
||||||
|
@ -130,6 +132,26 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SimpleWorkerContext fromPackage(NpmPackage pi, boolean allowDuplicates) throws FileNotFoundException, IOException, FHIRException {
|
||||||
|
SimpleWorkerContext res = new SimpleWorkerContext();
|
||||||
|
res.setAllowLoadingDuplicates(allowDuplicates);
|
||||||
|
res.loadFromPackage(pi, null);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SimpleWorkerContext fromPackage(NpmPackage pi) throws FileNotFoundException, IOException, FHIRException {
|
||||||
|
SimpleWorkerContext res = new SimpleWorkerContext();
|
||||||
|
res.loadFromPackage(pi, null);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SimpleWorkerContext fromPackage(NpmPackage pi, IContextResourceLoader loader) throws FileNotFoundException, IOException, FHIRException {
|
||||||
|
SimpleWorkerContext res = new SimpleWorkerContext();
|
||||||
|
res.setAllowLoadingDuplicates(true);
|
||||||
|
res.loadFromPackage(pi, loader);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
public static SimpleWorkerContext fromPack(String path, boolean allowDuplicates) throws FileNotFoundException, IOException, FHIRException {
|
public static SimpleWorkerContext fromPack(String path, boolean allowDuplicates) throws FileNotFoundException, IOException, FHIRException {
|
||||||
SimpleWorkerContext res = new SimpleWorkerContext();
|
SimpleWorkerContext res = new SimpleWorkerContext();
|
||||||
res.setAllowLoadingDuplicates(allowDuplicates);
|
res.setAllowLoadingDuplicates(allowDuplicates);
|
||||||
|
@ -224,29 +246,43 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadFromFileJson(InputStream stream, String name, IContextResourceLoader loader) throws IOException, FHIRException {
|
private void loadFromFileJson(InputStream stream, String name, IContextResourceLoader loader) throws IOException, FHIRException {
|
||||||
Bundle f;
|
Bundle f = null;
|
||||||
try {
|
try {
|
||||||
if (loader != null)
|
if (loader != null)
|
||||||
f = loader.loadBundle(stream, true);
|
f = loader.loadBundle(stream, true);
|
||||||
else {
|
else {
|
||||||
JsonParser json = new JsonParser();
|
JsonParser json = new JsonParser();
|
||||||
f = (Bundle) json.parse(stream);
|
Resource r = json.parse(stream);
|
||||||
|
if (r instanceof Bundle)
|
||||||
|
f = (Bundle) r;
|
||||||
|
else
|
||||||
|
cacheResource(r);
|
||||||
}
|
}
|
||||||
} catch (FHIRFormatError e1) {
|
} catch (FHIRFormatError e1) {
|
||||||
throw new org.hl7.fhir.exceptions.FHIRFormatError(e1.getMessage(), e1);
|
throw new org.hl7.fhir.exceptions.FHIRFormatError(e1.getMessage(), e1);
|
||||||
}
|
}
|
||||||
for (BundleEntryComponent e : f.getEntry()) {
|
if (f != null)
|
||||||
|
for (BundleEntryComponent e : f.getEntry()) {
|
||||||
if (e.getFullUrl() == null) {
|
cacheResource(e.getResource());
|
||||||
logger.logDebugMessage(LogCategory.CONTEXT, "unidentified resource in " + name+" (no fullUrl)");
|
|
||||||
}
|
|
||||||
cacheResource(e.getResource());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadFromPack(String path, IContextResourceLoader loader) throws FileNotFoundException, IOException, FHIRException {
|
private void loadFromPack(String path, IContextResourceLoader loader) throws FileNotFoundException, IOException, FHIRException {
|
||||||
loadFromStream(new CSFileInputStream(path), loader);
|
loadFromStream(new CSFileInputStream(path), loader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void loadFromPackage(NpmPackage pi, IContextResourceLoader loader, String... types) throws FileNotFoundException, IOException, FHIRException {
|
||||||
|
if (types.length == 0)
|
||||||
|
types = new String[] { "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"};
|
||||||
|
for (String s : pi.list("package")) {
|
||||||
|
if (s.contains("-") && s.endsWith(".json")) {
|
||||||
|
String t = s.substring(0, s.indexOf("-"));
|
||||||
|
if (Utilities.existsInList(t, types)) {
|
||||||
|
loadDefinitionItem(s, pi.load("package", s), loader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void loadFromFile(String file, IContextResourceLoader loader) throws IOException, FHIRException {
|
public void loadFromFile(String file, IContextResourceLoader loader) throws IOException, FHIRException {
|
||||||
loadDefinitionItem(file, new CSFileInputStream(file), loader);
|
loadDefinitionItem(file, new CSFileInputStream(file), loader);
|
||||||
|
@ -423,6 +459,18 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void loadBinariesFromFolder(String folder) throws FileNotFoundException, Exception {
|
||||||
|
for (String n : new File(folder).list()) {
|
||||||
|
loadBytes(n, new FileInputStream(Utilities.path(folder, n)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadBinariesFromFolder(NpmPackage pi) throws FileNotFoundException, Exception {
|
||||||
|
for (String n : pi.list("other")) {
|
||||||
|
loadBytes(n, pi.load("other", n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void loadFromFolder(String folder) throws FileNotFoundException, Exception {
|
public void loadFromFolder(String folder) throws FileNotFoundException, Exception {
|
||||||
for (String n : new File(folder).list()) {
|
for (String n : new File(folder).list()) {
|
||||||
if (n.endsWith(".json"))
|
if (n.endsWith(".json"))
|
||||||
|
@ -507,12 +555,13 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
|
||||||
List<ValidationMessage> msgs = new ArrayList<ValidationMessage>();
|
List<ValidationMessage> msgs = new ArrayList<ValidationMessage>();
|
||||||
List<String> errors = new ArrayList<String>();
|
List<String> errors = new ArrayList<String>();
|
||||||
ProfileUtilities pu = new ProfileUtilities(this, msgs, this);
|
ProfileUtilities pu = new ProfileUtilities(this, msgs, this);
|
||||||
|
pu.setThrowException(false);
|
||||||
pu.sortDifferential(sd, p, p.getUrl(), errors);
|
pu.sortDifferential(sd, p, p.getUrl(), errors);
|
||||||
for (String err : errors)
|
for (String err : errors)
|
||||||
msgs.add(new ValidationMessage(Source.ProfileValidator, IssueType.EXCEPTION, p.getUserString("path"), "Error sorting Differential: "+err, ValidationMessage.IssueSeverity.ERROR));
|
msgs.add(new ValidationMessage(Source.ProfileValidator, IssueType.EXCEPTION, p.getUserString("path"), "Error sorting Differential: "+err, ValidationMessage.IssueSeverity.ERROR));
|
||||||
pu.generateSnapshot(sd, p, p.getUrl(), p.getName());
|
pu.generateSnapshot(sd, p, p.getUrl(), p.getName());
|
||||||
for (ValidationMessage msg : msgs) {
|
for (ValidationMessage msg : msgs) {
|
||||||
if (msg.getLevel() == ValidationMessage.IssueSeverity.ERROR || msg.getLevel() == ValidationMessage.IssueSeverity.FATAL)
|
if ((!ignoreProfileErrors && msg.getLevel() == ValidationMessage.IssueSeverity.ERROR) || msg.getLevel() == ValidationMessage.IssueSeverity.FATAL)
|
||||||
throw new DefinitionException("Profile "+p.getName()+" ("+p.getUrl()+"). Error generating snapshot: "+msg.getMessage());
|
throw new DefinitionException("Profile "+p.getName()+" ("+p.getUrl()+"). Error generating snapshot: "+msg.getMessage());
|
||||||
}
|
}
|
||||||
if (!p.hasSnapshot())
|
if (!p.hasSnapshot())
|
||||||
|
@ -531,6 +580,14 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
|
||||||
this.ucumService = ucumService;
|
this.ucumService = ucumService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isIgnoreProfileErrors() {
|
||||||
|
return ignoreProfileErrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIgnoreProfileErrors(boolean ignoreProfileErrors) {
|
||||||
|
this.ignoreProfileErrors = ignoreProfileErrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,426 @@
|
||||||
|
package org.hl7.fhir.r4.context;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.Charsets;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
|
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||||
|
import org.hl7.fhir.r4.context.IWorkerContext.ValidationResult;
|
||||||
|
import org.hl7.fhir.r4.formats.IParser.OutputStyle;
|
||||||
|
import org.hl7.fhir.r4.formats.JsonParser;
|
||||||
|
import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
|
||||||
|
import org.hl7.fhir.r4.model.CodeableConcept;
|
||||||
|
import org.hl7.fhir.r4.model.Coding;
|
||||||
|
import org.hl7.fhir.r4.model.UriType;
|
||||||
|
import org.hl7.fhir.r4.model.ValueSet;
|
||||||
|
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
|
||||||
|
import org.hl7.fhir.r4.model.ValueSet.ConceptSetFilterComponent;
|
||||||
|
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent;
|
||||||
|
import org.hl7.fhir.r4.terminologies.ValueSetExpander.TerminologyServiceErrorClass;
|
||||||
|
import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
||||||
|
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||||
|
import org.hl7.fhir.utilities.TextFile;
|
||||||
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
|
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonNull;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This implements a two level cache.
|
||||||
|
* - a temporary cache for remmbering previous local operations
|
||||||
|
* - a persistent cache for rembering tx server operations
|
||||||
|
*
|
||||||
|
* the cache is a series of pairs: a map, and a list. the map is the loaded cache, the list is the persiistent cache, carefully maintained in order for version control consistency
|
||||||
|
*
|
||||||
|
* @author graha
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TerminologyCache {
|
||||||
|
public static final boolean TRANSIENT = false;
|
||||||
|
public static final boolean PERMANENT = true;
|
||||||
|
private static final String NAME_FOR_NO_SYSTEM = "all-systems";
|
||||||
|
private static final String ENTRY_MARKER = "-------------------------------------------------------------------------------------";
|
||||||
|
private static final String BREAK = "####";
|
||||||
|
|
||||||
|
public class CacheToken {
|
||||||
|
private String name;
|
||||||
|
private String key;
|
||||||
|
private String request;
|
||||||
|
public void setName(String n) {
|
||||||
|
if (name == null)
|
||||||
|
name = n;
|
||||||
|
else if (!n.equals(name))
|
||||||
|
name = NAME_FOR_NO_SYSTEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CacheEntry {
|
||||||
|
private String request;
|
||||||
|
private boolean persistent;
|
||||||
|
private ValidationResult v;
|
||||||
|
private ValueSetExpansionOutcome e;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class NamedCache {
|
||||||
|
private String name;
|
||||||
|
private List<CacheEntry> list = new ArrayList<CacheEntry>(); // persistent entries
|
||||||
|
private Map<String, CacheEntry> map = new HashMap<String, CacheEntry>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Object lock;
|
||||||
|
private String folder;
|
||||||
|
private Map<String, NamedCache> caches = new HashMap<String, NamedCache>();
|
||||||
|
|
||||||
|
// use lock from the context
|
||||||
|
public TerminologyCache(Object lock, String folder) throws FileNotFoundException, IOException, FHIRException {
|
||||||
|
super();
|
||||||
|
this.lock = lock;
|
||||||
|
this.folder = folder;
|
||||||
|
if (folder != null)
|
||||||
|
load();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CacheToken generateValidationToken(Coding code, ValueSet vs) {
|
||||||
|
CacheToken ct = new CacheToken();
|
||||||
|
if (code.hasSystem())
|
||||||
|
ct.name = getNameForSystem(code.getSystem());
|
||||||
|
else
|
||||||
|
ct.name = NAME_FOR_NO_SYSTEM;
|
||||||
|
JsonParser json = new JsonParser();
|
||||||
|
json.setOutputStyle(OutputStyle.PRETTY);
|
||||||
|
ValueSet vsc = getVSEssense(vs);
|
||||||
|
try {
|
||||||
|
ct.request = "{\"code\" : "+json.composeString(code, "code")+", \"valueSet\" :"+(vsc == null ? "null" : json.composeString(vsc))+"}";
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new Error(e);
|
||||||
|
}
|
||||||
|
ct.key = String.valueOf(hashNWS(ct.request));
|
||||||
|
return ct;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CacheToken generateValidationToken(CodeableConcept code, ValueSet vs) {
|
||||||
|
CacheToken ct = new CacheToken();
|
||||||
|
for (Coding c : code.getCoding()) {
|
||||||
|
if (c.hasSystem())
|
||||||
|
ct.setName(getNameForSystem(c.getSystem()));
|
||||||
|
}
|
||||||
|
JsonParser json = new JsonParser();
|
||||||
|
json.setOutputStyle(OutputStyle.PRETTY);
|
||||||
|
ValueSet vsc = getVSEssense(vs);
|
||||||
|
try {
|
||||||
|
ct.request = "{\"code\" : "+json.composeString(code, "codeableConcept")+", \"valueSet\" :"+json.composeString(vsc)+"}";
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new Error(e);
|
||||||
|
}
|
||||||
|
ct.key = String.valueOf(hashNWS(ct.request));
|
||||||
|
return ct;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueSet getVSEssense(ValueSet vs) {
|
||||||
|
if (vs == null)
|
||||||
|
return null;
|
||||||
|
ValueSet vsc = new ValueSet();
|
||||||
|
vsc.setCompose(vs.getCompose());
|
||||||
|
if (vs.hasExpansion()) {
|
||||||
|
vsc.getExpansion().getParameter().addAll(vs.getExpansion().getParameter());
|
||||||
|
vsc.getExpansion().getContains().addAll(vs.getExpansion().getContains());
|
||||||
|
}
|
||||||
|
return vsc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CacheToken generateExpandToken(ValueSet vs, boolean heirarchical) {
|
||||||
|
CacheToken ct = new CacheToken();
|
||||||
|
ValueSet vsc = getVSEssense(vs);
|
||||||
|
for (ConceptSetComponent inc : vs.getCompose().getInclude())
|
||||||
|
if (inc.hasSystem())
|
||||||
|
ct.setName(getNameForSystem(inc.getSystem()));
|
||||||
|
for (ConceptSetComponent inc : vs.getCompose().getExclude())
|
||||||
|
if (inc.hasSystem())
|
||||||
|
ct.setName(getNameForSystem(inc.getSystem()));
|
||||||
|
for (ValueSetExpansionContainsComponent inc : vs.getExpansion().getContains())
|
||||||
|
if (inc.hasSystem())
|
||||||
|
ct.setName(getNameForSystem(inc.getSystem()));
|
||||||
|
JsonParser json = new JsonParser();
|
||||||
|
json.setOutputStyle(OutputStyle.PRETTY);
|
||||||
|
try {
|
||||||
|
ct.request = "{\"hierarchical\" : "+(heirarchical ? "true" : "false")+", \"valueSet\" :"+json.composeString(vsc)+"}\r\n";
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new Error(e);
|
||||||
|
}
|
||||||
|
ct.key = String.valueOf(hashNWS(ct.request));
|
||||||
|
return ct;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getNameForSystem(String system) {
|
||||||
|
if (system.equals("http://snomed.info/sct"))
|
||||||
|
return "snomed";
|
||||||
|
if (system.equals("http://www.nlm.nih.gov/research/umls/rxnorm"))
|
||||||
|
return "rxnorm";
|
||||||
|
if (system.equals("http://loinc.org"))
|
||||||
|
return "loinc";
|
||||||
|
if (system.equals("http://unitsofmeasure.org"))
|
||||||
|
return "ucum";
|
||||||
|
if (system.startsWith("http://hl7.org/fhir/sid/"))
|
||||||
|
return system.substring(24).replace("/", "");
|
||||||
|
if (system.startsWith("urn:iso:std:iso:"))
|
||||||
|
return "iso"+system.substring(16).replace(":", "");
|
||||||
|
if (system.startsWith("http://terminology.hl7.org/CodeSystem/"))
|
||||||
|
return system.substring(38).replace("/", "");
|
||||||
|
if (system.startsWith("http://hl7.org/fhir/"))
|
||||||
|
return system.substring(20).replace("/", "");
|
||||||
|
if (system.equals("urn:ietf:bcp:47"))
|
||||||
|
return "lang";
|
||||||
|
if (system.equals("urn:ietf:bcp:13"))
|
||||||
|
return "mimetypes";
|
||||||
|
if (system.equals("urn:iso:std:iso:11073:10101"))
|
||||||
|
return "11073";
|
||||||
|
if (system.equals("http://dicom.nema.org/resources/ontology/DCM"))
|
||||||
|
return "dicom";
|
||||||
|
return system.replace("/", "_").replace(":", "_");
|
||||||
|
}
|
||||||
|
|
||||||
|
public NamedCache getNamedCache(CacheToken cacheToken) {
|
||||||
|
NamedCache nc = caches.get(cacheToken.name);
|
||||||
|
if (nc == null) {
|
||||||
|
nc = new NamedCache();
|
||||||
|
nc.name = cacheToken.name;
|
||||||
|
caches.put(nc.name, nc);
|
||||||
|
}
|
||||||
|
return nc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueSetExpansionOutcome getExpansion(CacheToken cacheToken) {
|
||||||
|
synchronized (lock) {
|
||||||
|
NamedCache nc = getNamedCache(cacheToken);
|
||||||
|
CacheEntry e = nc.map.get(cacheToken.key);
|
||||||
|
if (e == null)
|
||||||
|
return null;
|
||||||
|
else
|
||||||
|
return e.e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cacheExpansion(CacheToken cacheToken, ValueSetExpansionOutcome res, boolean persistent) {
|
||||||
|
synchronized (lock) {
|
||||||
|
NamedCache nc = getNamedCache(cacheToken);
|
||||||
|
CacheEntry e = new CacheEntry();
|
||||||
|
e.request = cacheToken.request;
|
||||||
|
e.persistent = persistent;
|
||||||
|
e.e = res;
|
||||||
|
store(cacheToken, persistent, nc, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void store(CacheToken cacheToken, boolean persistent, NamedCache nc, CacheEntry e) {
|
||||||
|
boolean n = nc.map.containsKey(cacheToken.key);
|
||||||
|
nc.map.put(cacheToken.key, e);
|
||||||
|
if (persistent) {
|
||||||
|
if (n) {
|
||||||
|
for (int i = nc.list.size()- 1; i>= 0; i--) {
|
||||||
|
if (nc.list.get(i).request.equals(e.request)) {
|
||||||
|
nc.list.remove(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nc.list.add(e);
|
||||||
|
save(nc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValidationResult getValidation(CacheToken cacheToken) {
|
||||||
|
synchronized (lock) {
|
||||||
|
NamedCache nc = getNamedCache(cacheToken);
|
||||||
|
CacheEntry e = nc.map.get(cacheToken.key);
|
||||||
|
if (e == null)
|
||||||
|
return null;
|
||||||
|
else
|
||||||
|
return e.v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cacheValidation(CacheToken cacheToken, ValidationResult res, boolean persistent) {
|
||||||
|
synchronized (lock) {
|
||||||
|
NamedCache nc = getNamedCache(cacheToken);
|
||||||
|
CacheEntry e = new CacheEntry();
|
||||||
|
e.request = cacheToken.request;
|
||||||
|
e.persistent = persistent;
|
||||||
|
e.v = res;
|
||||||
|
store(cacheToken, persistent, nc, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// persistence
|
||||||
|
|
||||||
|
public void save() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void save(NamedCache nc) {
|
||||||
|
if (folder == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
FileWriter sw = new FileWriter(new File(Utilities.path(folder, nc.name+".cache")));
|
||||||
|
sw.write(ENTRY_MARKER+"\r\n");
|
||||||
|
JsonParser json = new JsonParser();
|
||||||
|
json.setOutputStyle(OutputStyle.PRETTY);
|
||||||
|
for (CacheEntry ce : nc.list) {
|
||||||
|
sw.write(ce.request);
|
||||||
|
sw.write(BREAK+"\r\n");
|
||||||
|
if (ce.e != null) {
|
||||||
|
sw.write("e: {\r\n");
|
||||||
|
if (ce.e.getValueset() != null)
|
||||||
|
sw.write(" \"valueSet\" : "+json.composeString(ce.e.getValueset())+",\r\n");
|
||||||
|
sw.write(" \"error\" : \""+Utilities.escapeJson(ce.e.getError())+"\"\r\n}\r\n");
|
||||||
|
} else {
|
||||||
|
sw.write("v: {\r\n");
|
||||||
|
sw.write(" \"display\" : \""+Utilities.escapeJson(ce.v.getDisplay())+"\",\r\n");
|
||||||
|
sw.write(" \"severity\" : "+(ce.v.getSeverity() == null ? "null" : "\""+ce.v.getSeverity().toCode()+"\"")+",\r\n");
|
||||||
|
sw.write(" \"error\" : \""+Utilities.escapeJson(ce.v.getMessage())+"\"\r\n}\r\n");
|
||||||
|
}
|
||||||
|
sw.write(ENTRY_MARKER+"\r\n");
|
||||||
|
}
|
||||||
|
sw.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("error saving "+nc.name+": "+e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void load() throws FHIRException {
|
||||||
|
for (String fn : new File(folder).list()) {
|
||||||
|
if (fn.endsWith(".cache") && !fn.equals("validation.cache")) {
|
||||||
|
try {
|
||||||
|
// System.out.println("Load "+fn);
|
||||||
|
String title = fn.substring(0, fn.lastIndexOf("."));
|
||||||
|
NamedCache nc = new NamedCache();
|
||||||
|
nc.name = title;
|
||||||
|
caches.put(title, nc);
|
||||||
|
String src = TextFile.fileToString(Utilities.path(folder, fn));
|
||||||
|
int i = src.indexOf(ENTRY_MARKER);
|
||||||
|
while (i > -1) {
|
||||||
|
String s = src.substring(0, i);
|
||||||
|
src = src.substring(i+ENTRY_MARKER.length()+1);
|
||||||
|
i = src.indexOf(ENTRY_MARKER);
|
||||||
|
if (!Utilities.noString(s)) {
|
||||||
|
int j = s.indexOf(BREAK);
|
||||||
|
String q = s.substring(0, j);
|
||||||
|
String p = s.substring(j+BREAK.length()+1).trim();
|
||||||
|
CacheEntry ce = new CacheEntry();
|
||||||
|
ce.persistent = true;
|
||||||
|
ce.request = q;
|
||||||
|
boolean e = p.charAt(0) == 'e';
|
||||||
|
p = p.substring(3);
|
||||||
|
JsonObject o = (JsonObject) new com.google.gson.JsonParser().parse(p);
|
||||||
|
String error = loadJS(o.get("error"));
|
||||||
|
if (e) {
|
||||||
|
if (o.has("valueSet"))
|
||||||
|
ce.e = new ValueSetExpansionOutcome((ValueSet) new JsonParser().parse(o.getAsJsonObject("valueSet")), error, TerminologyServiceErrorClass.UNKNOWN);
|
||||||
|
else
|
||||||
|
ce.e = new ValueSetExpansionOutcome(error, TerminologyServiceErrorClass.UNKNOWN);
|
||||||
|
} else {
|
||||||
|
IssueSeverity severity = o.get("severity") instanceof JsonNull ? null : IssueSeverity.fromCode(o.get("severity").getAsString());
|
||||||
|
String display = loadJS(o.get("display"));
|
||||||
|
ce.v = new ValidationResult(severity, error, new ConceptDefinitionComponent().setDisplay(display));
|
||||||
|
}
|
||||||
|
nc.map.put(String.valueOf(hashNWS(ce.request)), ce);
|
||||||
|
nc.list.add(ce);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new FHIRException("Error loading "+fn+": "+e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String loadJS(JsonElement e) {
|
||||||
|
if (e == null)
|
||||||
|
return null;
|
||||||
|
if (!(e instanceof JsonPrimitive))
|
||||||
|
return null;
|
||||||
|
String s = e.getAsString();
|
||||||
|
if ("".equals(s))
|
||||||
|
return null;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String hashNWS(String s) {
|
||||||
|
return String.valueOf(s.replace("\r", "").replace("\n", "").replace(" ", "").hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
// management
|
||||||
|
|
||||||
|
public TerminologyCache copy() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String summary(ValueSet vs) {
|
||||||
|
if (vs == null)
|
||||||
|
return "null";
|
||||||
|
|
||||||
|
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
|
||||||
|
for (ConceptSetComponent cc : vs.getCompose().getInclude())
|
||||||
|
b.append("Include "+getIncSummary(cc));
|
||||||
|
for (ConceptSetComponent cc : vs.getCompose().getExclude())
|
||||||
|
b.append("Exclude "+getIncSummary(cc));
|
||||||
|
return b.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getIncSummary(ConceptSetComponent cc) {
|
||||||
|
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
|
||||||
|
for (UriType vs : cc.getValueSet())
|
||||||
|
b.append(vs.asStringValue());
|
||||||
|
String vsd = b.length() > 0 ? " where the codes are in the value sets ("+b.toString()+")" : "";
|
||||||
|
String system = cc.getSystem();
|
||||||
|
if (cc.hasConcept())
|
||||||
|
return Integer.toString(cc.getConcept().size())+" codes from "+system+vsd;
|
||||||
|
if (cc.hasFilter()) {
|
||||||
|
String s = "";
|
||||||
|
for (ConceptSetFilterComponent f : cc.getFilter()) {
|
||||||
|
if (!Utilities.noString(s))
|
||||||
|
s = s + " & ";
|
||||||
|
s = s + f.getProperty()+" "+f.getOp().toCode()+" "+f.getValue();
|
||||||
|
}
|
||||||
|
return "from "+system+" where "+s+vsd;
|
||||||
|
}
|
||||||
|
return "All codes from "+system+vsd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String summary(Coding code) {
|
||||||
|
return code.getSystem()+"#"+code.getCode()+": \""+code.getDisplay()+"\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String summary(CodeableConcept code) {
|
||||||
|
StringBuilder b = new StringBuilder();
|
||||||
|
b.append("{");
|
||||||
|
boolean first = true;
|
||||||
|
for (Coding c : code.getCoding()) {
|
||||||
|
if (first) first = false; else b.append(",");
|
||||||
|
b.append(summary(c));
|
||||||
|
}
|
||||||
|
b.append("}: \"");
|
||||||
|
b.append(code.getText());
|
||||||
|
b.append("\"");
|
||||||
|
return b.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -21,6 +21,8 @@ import org.hl7.fhir.r4.model.Type;
|
||||||
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent;
|
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent;
|
||||||
import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
||||||
import org.hl7.fhir.exceptions.FHIRException;
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
|
import org.hl7.fhir.utilities.ElementDecoration;
|
||||||
|
import org.hl7.fhir.utilities.ElementDecoration.DecorationType;
|
||||||
import org.hl7.fhir.utilities.Utilities;
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
|
import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
|
||||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||||
|
@ -470,9 +472,30 @@ public class Element extends Base {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markValidation(StructureDefinition profile, ElementDefinition definition) {
|
public void clearDecorations() {
|
||||||
|
clearUserData("fhir.decorations");
|
||||||
|
for (Element e : children)
|
||||||
|
e.clearDecorations();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void markValidation(StructureDefinition profile, ElementDefinition definition) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<ElementDecoration> decorations = (List<ElementDecoration>) getUserData("fhir.decorations");
|
||||||
|
if (decorations == null) {
|
||||||
|
decorations = new ArrayList<ElementDecoration>();
|
||||||
|
setUserData("fhir.decorations", decorations);
|
||||||
|
}
|
||||||
|
decorations.add(new ElementDecoration(DecorationType.TYPE, profile.getUserString("path"), definition.getPath()));
|
||||||
|
if (tail(definition.getId()).contains(":")) {
|
||||||
|
String[] details = tail(definition.getId()).split("\\:");
|
||||||
|
decorations.add(new ElementDecoration(DecorationType.SLICE, null, details[1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String tail(String id) {
|
||||||
|
return id.contains(".") ? id.substring(id.lastIndexOf(".")+1) : id;
|
||||||
|
}
|
||||||
|
|
||||||
public Element getNamedChild(String name) {
|
public Element getNamedChild(String name) {
|
||||||
if (children == null)
|
if (children == null)
|
||||||
return null;
|
return null;
|
||||||
|
@ -660,7 +683,7 @@ public class Element extends Base {
|
||||||
private List<ElementDefinition> children;
|
private List<ElementDefinition> children;
|
||||||
public ElementSortComparator(Element e, Property property) {
|
public ElementSortComparator(Element e, Property property) {
|
||||||
String tn = e.getType();
|
String tn = e.getType();
|
||||||
StructureDefinition sd = property.getContext().fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(tn));
|
StructureDefinition sd = property.getContext().fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(tn, property.getContext().getOverrideVersionNs()));
|
||||||
if (sd != null && !sd.getAbstract())
|
if (sd != null && !sd.getAbstract())
|
||||||
children = sd.getSnapshot().getElement();
|
children = sd.getSnapshot().getElement();
|
||||||
else
|
else
|
||||||
|
|
|
@ -80,7 +80,7 @@ public class JsonParser extends ParserBase {
|
||||||
assert (map.containsKey(obj));
|
assert (map.containsKey(obj));
|
||||||
return parse(obj);
|
return parse(obj);
|
||||||
} else {
|
} else {
|
||||||
JsonObject obj = (JsonObject) new com.google.gson.JsonParser().parse(source);
|
JsonObject obj = JsonTrackingParser.parse(source, null); // (JsonObject) new com.google.gson.JsonParser().parse(source);
|
||||||
// assert (map.containsKey(obj));
|
// assert (map.containsKey(obj));
|
||||||
return parse(obj);
|
return parse(obj);
|
||||||
}
|
}
|
||||||
|
@ -284,7 +284,7 @@ public class JsonParser extends ParserBase {
|
||||||
logError(line(res), col(res), npath, IssueType.INVALID, "Unable to find resourceType property", IssueSeverity.FATAL);
|
logError(line(res), col(res), npath, IssueType.INVALID, "Unable to find resourceType property", IssueSeverity.FATAL);
|
||||||
} else {
|
} else {
|
||||||
String name = rt.getAsString();
|
String name = rt.getAsString();
|
||||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(name));
|
StructureDefinition sd = context.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(name, context.getOverrideVersionNs()));
|
||||||
if (sd == null)
|
if (sd == null)
|
||||||
throw new FHIRFormatError("Contained resource does not appear to be a FHIR resource (unknown name '"+name+"')");
|
throw new FHIRFormatError("Contained resource does not appear to be a FHIR resource (unknown name '"+name+"')");
|
||||||
parent.updateProperty(new Property(context, sd.getSnapshot().getElement().get(0), sd), SpecialElement.fromProperty(parent.getProperty()), elementProperty);
|
parent.updateProperty(new Property(context, sd.getSnapshot().getElement().get(0), sd), SpecialElement.fromProperty(parent.getProperty()), elementProperty);
|
||||||
|
@ -447,7 +447,11 @@ public class JsonParser extends ParserBase {
|
||||||
else if (Utilities.existsInList(type, "integer", "unsignedInt", "positiveInt"))
|
else if (Utilities.existsInList(type, "integer", "unsignedInt", "positiveInt"))
|
||||||
json.value(new Integer(item.getValue()));
|
json.value(new Integer(item.getValue()));
|
||||||
else if (Utilities.existsInList(type, "decimal"))
|
else if (Utilities.existsInList(type, "decimal"))
|
||||||
json.value(new BigDecimal(item.getValue()));
|
try {
|
||||||
|
json.value(new BigDecimal(item.getValue()));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new NumberFormatException("error writing number '"+item.getValue()+"' to JSON");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
json.value(item.getValue());
|
json.value(item.getValue());
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ public class ObjectConverter {
|
||||||
if (base == null)
|
if (base == null)
|
||||||
return null;
|
return null;
|
||||||
String tn = base.fhirType();
|
String tn = base.fhirType();
|
||||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(tn));
|
StructureDefinition sd = context.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(tn, context.getOverrideVersionNs()));
|
||||||
if (sd == null)
|
if (sd == null)
|
||||||
throw new FHIRException("Unable to find definition for type "+tn);
|
throw new FHIRException("Unable to find definition for type "+tn);
|
||||||
Element res = new Element(property.getName(), property);
|
Element res = new Element(property.getName(), property);
|
||||||
|
@ -86,7 +86,7 @@ public class ObjectConverter {
|
||||||
ByteArrayOutputStream bo = new ByteArrayOutputStream();
|
ByteArrayOutputStream bo = new ByteArrayOutputStream();
|
||||||
try {
|
try {
|
||||||
new JsonParser(context).compose(element, bo, OutputStyle.NORMAL, null);
|
new JsonParser(context).compose(element, bo, OutputStyle.NORMAL, null);
|
||||||
TextFile.bytesToFile(bo.toByteArray(), "c:\\temp\\json.json");
|
// TextFile.bytesToFile(bo.toByteArray(), "c:\\temp\\json.json");
|
||||||
return new org.hl7.fhir.r4.formats.JsonParser().parse(bo.toByteArray());
|
return new org.hl7.fhir.r4.formats.JsonParser().parse(bo.toByteArray());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// won't happen
|
// won't happen
|
||||||
|
|
|
@ -3,13 +3,16 @@ package org.hl7.fhir.r4.elementmodel;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hl7.fhir.r4.context.IWorkerContext;
|
import org.hl7.fhir.r4.context.IWorkerContext;
|
||||||
import org.hl7.fhir.r4.formats.FormatUtilities;
|
import org.hl7.fhir.r4.formats.FormatUtilities;
|
||||||
import org.hl7.fhir.r4.formats.IParser.OutputStyle;
|
import org.hl7.fhir.r4.formats.IParser.OutputStyle;
|
||||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||||
import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind;
|
import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind;
|
||||||
|
import org.hl7.fhir.r4.model.StructureDefinition.TypeDerivationRule;
|
||||||
import org.hl7.fhir.r4.utils.ToolingExtensions;
|
import org.hl7.fhir.r4.utils.ToolingExtensions;
|
||||||
import org.hl7.fhir.exceptions.DefinitionException;
|
import org.hl7.fhir.exceptions.DefinitionException;
|
||||||
import org.hl7.fhir.exceptions.FHIRException;
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
|
@ -33,7 +36,7 @@ public abstract class ParserBase {
|
||||||
public boolean isPrimitive(String code) {
|
public boolean isPrimitive(String code) {
|
||||||
return Utilities.existsInList(code, "boolean", "integer", "string", "decimal", "uri", "base64Binary", "instant", "date", "dateTime", "time", "code", "oid", "id", "markdown", "unsignedInt", "positiveInt", "xhtml", "url", "canonical");
|
return Utilities.existsInList(code, "boolean", "integer", "string", "decimal", "uri", "base64Binary", "instant", "date", "dateTime", "time", "code", "oid", "id", "markdown", "unsignedInt", "positiveInt", "xhtml", "url", "canonical");
|
||||||
|
|
||||||
// StructureDefinition sd = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/"+code);
|
// StructureDefinition sd = context.fetchTypeDefinition(code);
|
||||||
// return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
|
// return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +44,8 @@ public abstract class ParserBase {
|
||||||
protected ValidationPolicy policy;
|
protected ValidationPolicy policy;
|
||||||
protected List<ValidationMessage> errors;
|
protected List<ValidationMessage> errors;
|
||||||
protected ILinkResolver linkResolver;
|
protected ILinkResolver linkResolver;
|
||||||
|
protected boolean showDecorations;
|
||||||
|
|
||||||
public ParserBase(IWorkerContext context) {
|
public ParserBase(IWorkerContext context) {
|
||||||
super();
|
super();
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
@ -77,7 +81,7 @@ public abstract class ParserBase {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
for (StructureDefinition sd : context.allStructures()) {
|
for (StructureDefinition sd : context.allStructures()) {
|
||||||
if (name.equals(sd.getIdElement().getIdPart()) && !sd.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition/de-")) {
|
if (name.equals(sd.getType()) && sd.getDerivation() == TypeDerivationRule.SPECIALIZATION && !sd.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition/de-")) {
|
||||||
if((ns == null || ns.equals(FormatUtilities.FHIR_NS)) && !ToolingExtensions.hasExtension(sd, "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace"))
|
if((ns == null || ns.equals(FormatUtilities.FHIR_NS)) && !ToolingExtensions.hasExtension(sd, "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace"))
|
||||||
return sd;
|
return sd;
|
||||||
String sns = ToolingExtensions.readStringExtension(sd, "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace");
|
String sns = ToolingExtensions.readStringExtension(sd, "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace");
|
||||||
|
@ -101,7 +105,7 @@ public abstract class ParserBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (StructureDefinition sd : context.allStructures()) {
|
for (StructureDefinition sd : context.allStructures()) {
|
||||||
if (name.equals(sd.getIdElement().getIdPart())) {
|
if (name.equals(sd.getType()) && sd.getDerivation() == TypeDerivationRule.SPECIALIZATION) {
|
||||||
return sd;
|
return sd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,7 +122,13 @@ public abstract class ParserBase {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isShowDecorations() {
|
||||||
|
return showDecorations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShowDecorations(boolean showDecorations) {
|
||||||
|
this.showDecorations = showDecorations;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import org.hl7.fhir.r4.model.StructureDefinition;
|
||||||
import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind;
|
import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind;
|
||||||
import org.hl7.fhir.r4.model.TypeDetails;
|
import org.hl7.fhir.r4.model.TypeDetails;
|
||||||
import org.hl7.fhir.r4.utils.ToolingExtensions;
|
import org.hl7.fhir.r4.utils.ToolingExtensions;
|
||||||
|
import org.hl7.fhir.r4.utils.TypesUtilities;
|
||||||
import org.hl7.fhir.utilities.Utilities;
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.hl7.fhir.exceptions.DefinitionException;
|
import org.hl7.fhir.exceptions.DefinitionException;
|
||||||
|
@ -88,7 +89,10 @@ public class Property {
|
||||||
} else
|
} else
|
||||||
throw new Error("logic error, gettype when types > 1, name mismatch for "+elementName+" on at "+ed.getPath());
|
throw new Error("logic error, gettype when types > 1, name mismatch for "+elementName+" on at "+ed.getPath());
|
||||||
} else if (ed.getType().get(0).getCode() == null) {
|
} else if (ed.getType().get(0).getCode() == null) {
|
||||||
return structure.getId();
|
if (Utilities.existsInList(ed.getId(), "Element.id", "Extension.url"))
|
||||||
|
return "string";
|
||||||
|
else
|
||||||
|
return structure.getId();
|
||||||
} else
|
} else
|
||||||
return ed.getType().get(0).getCode();
|
return ed.getType().get(0).getCode();
|
||||||
}
|
}
|
||||||
|
@ -135,8 +139,10 @@ public class Property {
|
||||||
* @param E.g. "integer"
|
* @param E.g. "integer"
|
||||||
*/
|
*/
|
||||||
public boolean isPrimitive(String code) {
|
public boolean isPrimitive(String code) {
|
||||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/"+code);
|
return TypesUtilities.isPrimitive(code);
|
||||||
return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
|
// was this... but this can be very inefficient compared to hard coding the list
|
||||||
|
// StructureDefinition sd = context.fetchTypeDefinition(code);
|
||||||
|
// return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String lowFirst(String t) {
|
private String lowFirst(String t) {
|
||||||
|
@ -191,7 +197,7 @@ public class Property {
|
||||||
return false;
|
return false;
|
||||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, structure.getUrl().substring(0, structure.getUrl().lastIndexOf("/")+1)+getType(name));
|
StructureDefinition sd = context.fetchResource(StructureDefinition.class, structure.getUrl().substring(0, structure.getUrl().lastIndexOf("/")+1)+getType(name));
|
||||||
if (sd == null)
|
if (sd == null)
|
||||||
sd = context.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(getType(name)));
|
sd = context.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(getType(name), context.getOverrideVersionNs()));
|
||||||
if (sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE)
|
if (sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE)
|
||||||
return true;
|
return true;
|
||||||
if (sd == null || sd.getKind() != StructureDefinitionKind.LOGICAL)
|
if (sd == null || sd.getKind() != StructureDefinitionKind.LOGICAL)
|
||||||
|
@ -274,7 +280,7 @@ public class Property {
|
||||||
assert aType.getProfile().size() == 1;
|
assert aType.getProfile().size() == 1;
|
||||||
url = aType.getProfile().get(0).getValue();
|
url = aType.getProfile().get(0).getValue();
|
||||||
} else {
|
} else {
|
||||||
url = ProfileUtilities.sdNs(t);
|
url = ProfileUtilities.sdNs(t, context.getOverrideVersionNs());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.hl7.fhir.r4.elementmodel;
|
package org.hl7.fhir.r4.elementmodel;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
@ -7,8 +8,10 @@ import java.io.UnsupportedEncodingException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import javax.sql.rowset.spi.XmlWriter;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.parsers.SAXParser;
|
import javax.xml.parsers.SAXParser;
|
||||||
|
@ -33,9 +36,12 @@ import org.hl7.fhir.r4.utils.formats.XmlLocationData;
|
||||||
import org.hl7.fhir.exceptions.DefinitionException;
|
import org.hl7.fhir.exceptions.DefinitionException;
|
||||||
import org.hl7.fhir.exceptions.FHIRException;
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||||
|
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||||
|
import org.hl7.fhir.utilities.ElementDecoration;
|
||||||
import org.hl7.fhir.utilities.Utilities;
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
||||||
|
import org.hl7.fhir.utilities.xhtml.CDANarrativeFormat;
|
||||||
import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
|
import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
|
||||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||||
import org.hl7.fhir.utilities.xhtml.XhtmlParser;
|
import org.hl7.fhir.utilities.xhtml.XhtmlParser;
|
||||||
|
@ -47,6 +53,8 @@ import org.w3c.dom.Node;
|
||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
import org.xml.sax.XMLReader;
|
import org.xml.sax.XMLReader;
|
||||||
|
|
||||||
|
import com.sun.webkit.ContextMenu.ShowContext;
|
||||||
|
|
||||||
public class XmlParser extends ParserBase {
|
public class XmlParser extends ParserBase {
|
||||||
private boolean allowXsiLocation;
|
private boolean allowXsiLocation;
|
||||||
|
|
||||||
|
@ -63,7 +71,6 @@ public class XmlParser extends ParserBase {
|
||||||
this.allowXsiLocation = allowXsiLocation;
|
this.allowXsiLocation = allowXsiLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Element parse(InputStream stream) throws FHIRFormatError, DefinitionException, FHIRException, IOException {
|
public Element parse(InputStream stream) throws FHIRFormatError, DefinitionException, FHIRException, IOException {
|
||||||
Document doc = null;
|
Document doc = null;
|
||||||
try {
|
try {
|
||||||
|
@ -115,7 +122,7 @@ public class XmlParser extends ParserBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkForProcessingInstruction(Document document) throws FHIRFormatError {
|
private void checkForProcessingInstruction(Document document) throws FHIRFormatError {
|
||||||
if (policy == ValidationPolicy.EVERYTHING) {
|
if (policy == ValidationPolicy.EVERYTHING && FormatUtilities.FHIR_NS.equals(document.getDocumentElement().getNamespaceURI())) {
|
||||||
Node node = document.getFirstChild();
|
Node node = document.getFirstChild();
|
||||||
while (node != null) {
|
while (node != null) {
|
||||||
if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE)
|
if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE)
|
||||||
|
@ -192,7 +199,7 @@ public class XmlParser extends ParserBase {
|
||||||
|
|
||||||
private void checkElement(org.w3c.dom.Element element, String path, Property prop) throws FHIRFormatError {
|
private void checkElement(org.w3c.dom.Element element, String path, Property prop) throws FHIRFormatError {
|
||||||
if (policy == ValidationPolicy.EVERYTHING) {
|
if (policy == ValidationPolicy.EVERYTHING) {
|
||||||
if (empty(element))
|
if (empty(element) && FormatUtilities.FHIR_NS.equals(element.getNamespaceURI())) // this rule only applies to FHIR Content
|
||||||
logError(line(element), col(element), path, IssueType.INVALID, "Element must have some content", IssueSeverity.ERROR);
|
logError(line(element), col(element), path, IssueType.INVALID, "Element must have some content", IssueSeverity.ERROR);
|
||||||
String ns = FormatUtilities.FHIR_NS;
|
String ns = FormatUtilities.FHIR_NS;
|
||||||
if (ToolingExtensions.hasExtension(prop.getDefinition(), "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace"))
|
if (ToolingExtensions.hasExtension(prop.getDefinition(), "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace"))
|
||||||
|
@ -237,13 +244,22 @@ public class XmlParser extends ParserBase {
|
||||||
if (property != null) {
|
if (property != null) {
|
||||||
String av = attr.getNodeValue();
|
String av = attr.getNodeValue();
|
||||||
if (ToolingExtensions.hasExtension(property.getDefinition(), "http://www.healthintersections.com.au/fhir/StructureDefinition/elementdefinition-dateformat"))
|
if (ToolingExtensions.hasExtension(property.getDefinition(), "http://www.healthintersections.com.au/fhir/StructureDefinition/elementdefinition-dateformat"))
|
||||||
av = convertForDateFormat(ToolingExtensions.readStringExtension(property.getDefinition(), "http://www.healthintersections.com.au/fhir/StructureDefinition/elementdefinition-dateformat"), av);
|
av = convertForDateFormatFromExternal(ToolingExtensions.readStringExtension(property.getDefinition(), "http://www.healthintersections.com.au/fhir/StructureDefinition/elementdefinition-dateformat"), av);
|
||||||
if (property.getName().equals("value") && context.isPrimitive())
|
if (property.getName().equals("value") && context.isPrimitive())
|
||||||
context.setValue(av);
|
context.setValue(av);
|
||||||
else
|
else
|
||||||
context.getChildren().add(new Element(property.getName(), property, property.getType(), av).markLocation(line(node), col(node)));
|
context.getChildren().add(new Element(property.getName(), property, property.getType(), av).markLocation(line(node), col(node)));
|
||||||
} else if (!allowXsiLocation || !attr.getNodeName().endsWith(":schemaLocation") ) {
|
} else {
|
||||||
logError(line(node), col(node), path, IssueType.STRUCTURE, "Undefined attribute '@"+attr.getNodeName()+"' on "+node.getNodeName()+" for type "+context.fhirType()+" (properties = "+properties+")", IssueSeverity.ERROR);
|
boolean ok = false;
|
||||||
|
if (FormatUtilities.FHIR_NS.equals(node.getNamespaceURI())) {
|
||||||
|
if (attr.getLocalName().equals("schemaLocation") && FormatUtilities.NS_XSI.equals(attr.getNamespaceURI())) {
|
||||||
|
ok = ok || allowXsiLocation;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
ok = ok || (attr.getLocalName().equals("schemaLocation")); // xsi:schemalocation allowed for non FHIR content
|
||||||
|
ok = ok || (hasTypeAttr(context) && attr.getLocalName().equals("type") && FormatUtilities.NS_XSI.equals(attr.getNamespaceURI())); // xsi:type allowed if element says so
|
||||||
|
if (!ok)
|
||||||
|
logError(line(node), col(node), path, IssueType.STRUCTURE, "Undefined attribute '@"+attr.getNodeName()+"' on "+node.getNodeName()+" for type "+context.fhirType()+" (properties = "+properties+")", IssueSeverity.ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,8 +270,12 @@ public class XmlParser extends ParserBase {
|
||||||
Property property = getElementProp(properties, child.getLocalName());
|
Property property = getElementProp(properties, child.getLocalName());
|
||||||
if (property != null) {
|
if (property != null) {
|
||||||
if (!property.isChoice() && "xhtml".equals(property.getType())) {
|
if (!property.isChoice() && "xhtml".equals(property.getType())) {
|
||||||
XhtmlNode xhtml = new XhtmlParser().setValidatorMode(true).parseHtmlNode((org.w3c.dom.Element) child);
|
XhtmlNode xhtml;
|
||||||
context.getChildren().add(new Element("div", property, "xhtml", new XhtmlComposer(XhtmlComposer.XML, false).compose(xhtml)).setXhtml(xhtml).markLocation(line(child), col(child)));
|
if (property.getDefinition().hasRepresentation(PropertyRepresentation.CDATEXT))
|
||||||
|
xhtml = new CDANarrativeFormat().convert((org.w3c.dom.Element) child);
|
||||||
|
else
|
||||||
|
xhtml = new XhtmlParser().setValidatorMode(true).parseHtmlNode((org.w3c.dom.Element) child);
|
||||||
|
context.getChildren().add(new Element(property.getName(), property, "xhtml", new XhtmlComposer(XhtmlComposer.XML, false).compose(xhtml)).setXhtml(xhtml).markLocation(line(child), col(child)));
|
||||||
} else {
|
} else {
|
||||||
String npath = path+"/"+pathPrefix(child.getNamespaceURI())+child.getLocalName();
|
String npath = path+"/"+pathPrefix(child.getNamespaceURI())+child.getLocalName();
|
||||||
Element n = new Element(child.getLocalName(), property).markLocation(line(child), col(child));
|
Element n = new Element(child.getLocalName(), property).markLocation(line(child), col(child));
|
||||||
|
@ -328,7 +348,7 @@ public class XmlParser extends ParserBase {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String convertForDateFormat(String fmt, String av) throws FHIRException {
|
private String convertForDateFormatFromExternal(String fmt, String av) throws FHIRException {
|
||||||
if ("v3".equals(fmt)) {
|
if ("v3".equals(fmt)) {
|
||||||
DateTimeType d = DateTimeType.parseV3(av);
|
DateTimeType d = DateTimeType.parseV3(av);
|
||||||
return d.asStringValue();
|
return d.asStringValue();
|
||||||
|
@ -336,10 +356,18 @@ public class XmlParser extends ParserBase {
|
||||||
throw new FHIRException("Unknown Data format '"+fmt+"'");
|
throw new FHIRException("Unknown Data format '"+fmt+"'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String convertForDateFormatToExternal(String fmt, String av) throws FHIRException {
|
||||||
|
if ("v3".equals(fmt)) {
|
||||||
|
DateTimeType d = new DateTimeType(av);
|
||||||
|
return d.getAsV3();
|
||||||
|
} else
|
||||||
|
throw new FHIRException("Unknown Data format '"+fmt+"'");
|
||||||
|
}
|
||||||
|
|
||||||
private void parseResource(String string, org.w3c.dom.Element container, Element parent, Property elementProperty) throws FHIRFormatError, DefinitionException, FHIRException, IOException {
|
private void parseResource(String string, org.w3c.dom.Element container, Element parent, Property elementProperty) throws FHIRFormatError, DefinitionException, FHIRException, IOException {
|
||||||
org.w3c.dom.Element res = XMLUtil.getFirstChild(container);
|
org.w3c.dom.Element res = XMLUtil.getFirstChild(container);
|
||||||
String name = res.getLocalName();
|
String name = res.getLocalName();
|
||||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(name));
|
StructureDefinition sd = context.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(name, context.getOverrideVersionNs()));
|
||||||
if (sd == null)
|
if (sd == null)
|
||||||
throw new FHIRFormatError("Contained resource does not appear to be a FHIR resource (unknown name '"+res.getLocalName()+"')");
|
throw new FHIRFormatError("Contained resource does not appear to be a FHIR resource (unknown name '"+res.getLocalName()+"')");
|
||||||
parent.updateProperty(new Property(context, sd.getSnapshot().getElement().get(0), sd), SpecialElement.fromProperty(parent.getProperty()), elementProperty);
|
parent.updateProperty(new Property(context, sd.getSnapshot().getElement().get(0), sd), SpecialElement.fromProperty(parent.getProperty()), elementProperty);
|
||||||
|
@ -365,14 +393,32 @@ public class XmlParser extends ParserBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAttr(Property property) {
|
private boolean isAttr(Property property) {
|
||||||
for (Enumeration<PropertyRepresentation> r : property.getDefinition().getRepresentation()) {
|
for (Enumeration<PropertyRepresentation> r : property.getDefinition().getRepresentation()) {
|
||||||
if (r.getValue() == PropertyRepresentation.XMLATTR) {
|
if (r.getValue() == PropertyRepresentation.XMLATTR) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isCdaText(Property property) {
|
||||||
|
for (Enumeration<PropertyRepresentation> r : property.getDefinition().getRepresentation()) {
|
||||||
|
if (r.getValue() == PropertyRepresentation.CDATEXT) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTypeAttr(Property property) {
|
||||||
|
for (Enumeration<PropertyRepresentation> r : property.getDefinition().getRepresentation()) {
|
||||||
|
if (r.getValue() == PropertyRepresentation.TYPEATTR) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isText(Property property) {
|
private boolean isText(Property property) {
|
||||||
for (Enumeration<PropertyRepresentation> r : property.getDefinition().getRepresentation()) {
|
for (Enumeration<PropertyRepresentation> r : property.getDefinition().getRepresentation()) {
|
||||||
|
@ -384,16 +430,30 @@ public class XmlParser extends ParserBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compose(Element e, OutputStream stream, OutputStyle style, String base) throws IOException {
|
public void compose(Element e, OutputStream stream, OutputStyle style, String base) throws IOException, FHIRException {
|
||||||
XMLWriter xml = new XMLWriter(stream, "UTF-8");
|
XMLWriter xml = new XMLWriter(stream, "UTF-8");
|
||||||
|
xml.setSortAttributes(false);
|
||||||
xml.setPretty(style == OutputStyle.PRETTY);
|
xml.setPretty(style == OutputStyle.PRETTY);
|
||||||
xml.start();
|
xml.start();
|
||||||
xml.setDefaultNamespace(e.getProperty().getNamespace());
|
xml.setDefaultNamespace(e.getProperty().getNamespace());
|
||||||
|
if (hasTypeAttr(e))
|
||||||
|
xml.namespace("http://www.w3.org/2001/XMLSchema-instance", "xsi");
|
||||||
composeElement(xml, e, e.getType(), true);
|
composeElement(xml, e, e.getType(), true);
|
||||||
xml.end();
|
xml.end();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasTypeAttr(Element e) {
|
||||||
|
if (isTypeAttr(e.getProperty()))
|
||||||
|
return true;
|
||||||
|
for (Element c : e.getChildren()) {
|
||||||
|
if (hasTypeAttr(c))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void compose(Element e, IXMLWriter xml) throws Exception {
|
public void compose(Element e, IXMLWriter xml) throws Exception {
|
||||||
xml.start();
|
xml.start();
|
||||||
xml.setDefaultNamespace(e.getProperty().getNamespace());
|
xml.setDefaultNamespace(e.getProperty().getNamespace());
|
||||||
|
@ -401,7 +461,14 @@ public class XmlParser extends ParserBase {
|
||||||
xml.end();
|
xml.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void composeElement(IXMLWriter xml, Element element, String elementName, boolean root) throws IOException {
|
private void composeElement(IXMLWriter xml, Element element, String elementName, boolean root) throws IOException, FHIRException {
|
||||||
|
if (showDecorations) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<ElementDecoration> decorations = (List<ElementDecoration>) element.getUserData("fhir.decorations");
|
||||||
|
if (decorations != null)
|
||||||
|
for (ElementDecoration d : decorations)
|
||||||
|
xml.decorate(d);
|
||||||
|
}
|
||||||
for (String s : element.getComments()) {
|
for (String s : element.getComments()) {
|
||||||
xml.comment(s, true);
|
xml.comment(s, true);
|
||||||
}
|
}
|
||||||
|
@ -413,12 +480,19 @@ public class XmlParser extends ParserBase {
|
||||||
xml.exit(elementName);
|
xml.exit(elementName);
|
||||||
} else if (element.isPrimitive() || (element.hasType() && isPrimitive(element.getType()))) {
|
} else if (element.isPrimitive() || (element.hasType() && isPrimitive(element.getType()))) {
|
||||||
if (element.getType().equals("xhtml")) {
|
if (element.getType().equals("xhtml")) {
|
||||||
xml.escapedText(element.getValue());
|
String rawXhtml = element.getValue();
|
||||||
|
if (isCdaText(element.getProperty())) {
|
||||||
|
new CDANarrativeFormat().convert(xml, element.getXhtml());
|
||||||
|
} else
|
||||||
|
xml.escapedText(rawXhtml);
|
||||||
} else if (isText(element.getProperty())) {
|
} else if (isText(element.getProperty())) {
|
||||||
if (linkResolver != null)
|
if (linkResolver != null)
|
||||||
xml.link(linkResolver.resolveProperty(element.getProperty()));
|
xml.link(linkResolver.resolveProperty(element.getProperty()));
|
||||||
xml.text(element.getValue());
|
xml.text(element.getValue());
|
||||||
} else {
|
} else {
|
||||||
|
if (isTypeAttr(element.getProperty()) && !Utilities.noString(element.getType())) {
|
||||||
|
xml.attribute("xsi:type", element.getType());
|
||||||
|
}
|
||||||
if (element.hasValue()) {
|
if (element.hasValue()) {
|
||||||
if (linkResolver != null)
|
if (linkResolver != null)
|
||||||
xml.link(linkResolver.resolveType(element.getType()));
|
xml.link(linkResolver.resolveType(element.getType()));
|
||||||
|
@ -432,14 +506,20 @@ public class XmlParser extends ParserBase {
|
||||||
composeElement(xml, child, child.getName(), false);
|
composeElement(xml, child, child.getName(), false);
|
||||||
xml.exit(elementName);
|
xml.exit(elementName);
|
||||||
} else
|
} else
|
||||||
xml.element(elementName);
|
xml.element(elementName);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (isTypeAttr(element.getProperty()) && !Utilities.noString(element.getType())) {
|
||||||
|
xml.attribute("xsi:type", element.getType());
|
||||||
|
}
|
||||||
for (Element child : element.getChildren()) {
|
for (Element child : element.getChildren()) {
|
||||||
if (isAttr(child.getProperty())) {
|
if (isAttr(child.getProperty())) {
|
||||||
if (linkResolver != null)
|
if (linkResolver != null)
|
||||||
xml.link(linkResolver.resolveType(child.getType()));
|
xml.link(linkResolver.resolveType(child.getType()));
|
||||||
xml.attribute(child.getName(), child.getValue());
|
String av = child.getValue();
|
||||||
|
if (ToolingExtensions.hasExtension(child.getProperty().getDefinition(), "http://www.healthintersections.com.au/fhir/StructureDefinition/elementdefinition-dateformat"))
|
||||||
|
av = convertForDateFormatToExternal(ToolingExtensions.readStringExtension(child.getProperty().getDefinition(), "http://www.healthintersections.com.au/fhir/StructureDefinition/elementdefinition-dateformat"), av);
|
||||||
|
xml.attribute(child.getName(), av);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (linkResolver != null)
|
if (linkResolver != null)
|
||||||
|
|
|
@ -26,6 +26,7 @@ public interface JsonCreator {
|
||||||
void value(Boolean value) throws IOException;
|
void value(Boolean value) throws IOException;
|
||||||
|
|
||||||
void value(BigDecimal value) throws IOException;
|
void value(BigDecimal value) throws IOException;
|
||||||
|
void valueNum(String value) throws IOException; // allow full control of representation
|
||||||
|
|
||||||
void value(Integer value) throws IOException;
|
void value(Integer value) throws IOException;
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,6 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
|
||||||
import com.google.gson.stream.JsonWriter;
|
|
||||||
|
|
||||||
public class JsonCreatorCanonical implements JsonCreator {
|
public class JsonCreatorCanonical implements JsonCreator {
|
||||||
|
|
||||||
public class JsonCanValue {
|
public class JsonCanValue {
|
||||||
|
@ -27,6 +25,14 @@ public class JsonCreatorCanonical implements JsonCreator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class JsonCanPresentedNumberValue extends JsonCanValue {
|
||||||
|
private String value;
|
||||||
|
private JsonCanPresentedNumberValue(String name, String value) {
|
||||||
|
super(name);
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class JsonCanIntegerValue extends JsonCanValue {
|
private class JsonCanIntegerValue extends JsonCanValue {
|
||||||
private Integer value;
|
private Integer value;
|
||||||
private JsonCanIntegerValue(String name, Integer value) {
|
private JsonCanIntegerValue(String name, Integer value) {
|
||||||
|
@ -74,12 +80,12 @@ public class JsonCreatorCanonical implements JsonCreator {
|
||||||
|
|
||||||
Stack<JsonCanObject> stack;
|
Stack<JsonCanObject> stack;
|
||||||
JsonCanObject root;
|
JsonCanObject root;
|
||||||
JsonWriter gson;
|
JsonCreatorDirect jj;
|
||||||
String name;
|
String name;
|
||||||
|
|
||||||
public JsonCreatorCanonical(OutputStreamWriter osw) {
|
public JsonCreatorCanonical(OutputStreamWriter osw) {
|
||||||
stack = new Stack<JsonCreatorCanonical.JsonCanObject>();
|
stack = new Stack<JsonCreatorCanonical.JsonCanObject>();
|
||||||
gson = new JsonWriter(osw);
|
jj = new JsonCreatorDirect(osw);
|
||||||
name = null;
|
name = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +99,7 @@ public class JsonCreatorCanonical implements JsonCreator {
|
||||||
public void setIndent(String indent) {
|
public void setIndent(String indent) {
|
||||||
if (!indent.equals(""))
|
if (!indent.equals(""))
|
||||||
throw new Error("do not use pretty when canonical is set");
|
throw new Error("do not use pretty when canonical is set");
|
||||||
gson.setIndent(indent);
|
jj.setIndent(indent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -135,6 +141,11 @@ public class JsonCreatorCanonical implements JsonCreator {
|
||||||
public void value(BigDecimal value) throws IOException {
|
public void value(BigDecimal value) throws IOException {
|
||||||
stack.peek().addProp(new JsonCanNumberValue(takeName(), value));
|
stack.peek().addProp(new JsonCanNumberValue(takeName(), value));
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public void valueNum(String value) throws IOException {
|
||||||
|
stack.peek().addProp(new JsonCanPresentedNumberValue(takeName(), value));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void value(Integer value) throws IOException {
|
public void value(Integer value) throws IOException {
|
||||||
|
@ -161,24 +172,26 @@ public class JsonCreatorCanonical implements JsonCreator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeObject(JsonCanObject obj) throws IOException {
|
private void writeObject(JsonCanObject obj) throws IOException {
|
||||||
gson.beginObject();
|
jj.beginObject();
|
||||||
List<String> names = new ArrayList<String>();
|
List<String> names = new ArrayList<String>();
|
||||||
for (JsonCanValue v : obj.children)
|
for (JsonCanValue v : obj.children)
|
||||||
names.add(v.name);
|
names.add(v.name);
|
||||||
Collections.sort(names);
|
Collections.sort(names);
|
||||||
for (String n : names) {
|
for (String n : names) {
|
||||||
gson.name(n);
|
jj.name(n);
|
||||||
JsonCanValue v = getPropForName(n, obj.children);
|
JsonCanValue v = getPropForName(n, obj.children);
|
||||||
if (v instanceof JsonCanNumberValue)
|
if (v instanceof JsonCanNumberValue)
|
||||||
gson.value(((JsonCanNumberValue) v).value);
|
jj.value(((JsonCanNumberValue) v).value);
|
||||||
|
else if (v instanceof JsonCanPresentedNumberValue)
|
||||||
|
jj.valueNum(((JsonCanPresentedNumberValue) v).value);
|
||||||
else if (v instanceof JsonCanIntegerValue)
|
else if (v instanceof JsonCanIntegerValue)
|
||||||
gson.value(((JsonCanIntegerValue) v).value);
|
jj.value(((JsonCanIntegerValue) v).value);
|
||||||
else if (v instanceof JsonCanBooleanValue)
|
else if (v instanceof JsonCanBooleanValue)
|
||||||
gson.value(((JsonCanBooleanValue) v).value);
|
jj.value(((JsonCanBooleanValue) v).value);
|
||||||
else if (v instanceof JsonCanStringValue)
|
else if (v instanceof JsonCanStringValue)
|
||||||
gson.value(((JsonCanStringValue) v).value);
|
jj.value(((JsonCanStringValue) v).value);
|
||||||
else if (v instanceof JsonCanNullValue)
|
else if (v instanceof JsonCanNullValue)
|
||||||
gson.nullValue();
|
jj.nullValue();
|
||||||
else if (v instanceof JsonCanObject) {
|
else if (v instanceof JsonCanObject) {
|
||||||
JsonCanObject o = (JsonCanObject) v;
|
JsonCanObject o = (JsonCanObject) v;
|
||||||
if (o.array)
|
if (o.array)
|
||||||
|
@ -188,7 +201,7 @@ public class JsonCreatorCanonical implements JsonCreator {
|
||||||
} else
|
} else
|
||||||
throw new Error("not possible");
|
throw new Error("not possible");
|
||||||
}
|
}
|
||||||
gson.endObject();
|
jj.endObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
private JsonCanValue getPropForName(String name, List<JsonCanValue> children) {
|
private JsonCanValue getPropForName(String name, List<JsonCanValue> children) {
|
||||||
|
@ -199,18 +212,18 @@ public class JsonCreatorCanonical implements JsonCreator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeArray(JsonCanObject arr) throws IOException {
|
private void writeArray(JsonCanObject arr) throws IOException {
|
||||||
gson.beginArray();
|
jj.beginArray();
|
||||||
for (JsonCanValue v : arr.children) {
|
for (JsonCanValue v : arr.children) {
|
||||||
if (v instanceof JsonCanNumberValue)
|
if (v instanceof JsonCanNumberValue)
|
||||||
gson.value(((JsonCanNumberValue) v).value);
|
jj.value(((JsonCanNumberValue) v).value);
|
||||||
else if (v instanceof JsonCanIntegerValue)
|
else if (v instanceof JsonCanIntegerValue)
|
||||||
gson.value(((JsonCanIntegerValue) v).value);
|
jj.value(((JsonCanIntegerValue) v).value);
|
||||||
else if (v instanceof JsonCanBooleanValue)
|
else if (v instanceof JsonCanBooleanValue)
|
||||||
gson.value(((JsonCanBooleanValue) v).value);
|
jj.value(((JsonCanBooleanValue) v).value);
|
||||||
else if (v instanceof JsonCanStringValue)
|
else if (v instanceof JsonCanStringValue)
|
||||||
gson.value(((JsonCanStringValue) v).value);
|
jj.value(((JsonCanStringValue) v).value);
|
||||||
else if (v instanceof JsonCanNullValue)
|
else if (v instanceof JsonCanNullValue)
|
||||||
gson.nullValue();
|
jj.nullValue();
|
||||||
else if (v instanceof JsonCanObject) {
|
else if (v instanceof JsonCanObject) {
|
||||||
JsonCanObject o = (JsonCanObject) v;
|
JsonCanObject o = (JsonCanObject) v;
|
||||||
if (o.array)
|
if (o.array)
|
||||||
|
@ -220,7 +233,7 @@ public class JsonCreatorCanonical implements JsonCreator {
|
||||||
} else
|
} else
|
||||||
throw new Error("not possible");
|
throw new Error("not possible");
|
||||||
}
|
}
|
||||||
gson.endArray();
|
jj.endArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,172 @@
|
||||||
|
package org.hl7.fhir.r4.formats;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A little implementation of a json write to replace Gson .... because Gson screws up decimal values, and *we care*
|
||||||
|
*
|
||||||
|
* @author Grahame Grieve
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class JsonCreatorDirect implements JsonCreator {
|
||||||
|
|
||||||
|
private Writer writer;
|
||||||
|
private boolean pretty;
|
||||||
|
private boolean named;
|
||||||
|
private boolean valued;
|
||||||
|
private int indent;
|
||||||
|
|
||||||
|
public JsonCreatorDirect(Writer writer) {
|
||||||
|
super();
|
||||||
|
this.writer = writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setIndent(String indent) {
|
||||||
|
this.pretty = !Utilities.noString(indent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beginObject() throws IOException {
|
||||||
|
checkState();
|
||||||
|
writer.write("{");
|
||||||
|
stepIn();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stepIn() throws IOException {
|
||||||
|
if (pretty) {
|
||||||
|
indent++;
|
||||||
|
writer.write("\r\n");
|
||||||
|
for (int i = 0; i < indent; i++) {
|
||||||
|
writer.write(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stepOut() throws IOException {
|
||||||
|
if (pretty) {
|
||||||
|
indent--;
|
||||||
|
writer.write("\r\n");
|
||||||
|
for (int i = 0; i < indent; i++) {
|
||||||
|
writer.write(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkState() throws IOException {
|
||||||
|
if (named) {
|
||||||
|
if (pretty)
|
||||||
|
writer.write(" : ");
|
||||||
|
else
|
||||||
|
writer.write(":");
|
||||||
|
named = false;
|
||||||
|
}
|
||||||
|
if (valued) {
|
||||||
|
writer.write(",");
|
||||||
|
if (pretty) {
|
||||||
|
writer.write("\r\n");
|
||||||
|
for (int i = 0; i < indent; i++) {
|
||||||
|
writer.write(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
valued = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endObject() throws IOException {
|
||||||
|
stepOut();
|
||||||
|
writer.write("}");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nullValue() throws IOException {
|
||||||
|
checkState();
|
||||||
|
writer.write("null");
|
||||||
|
valued = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void name(String name) throws IOException {
|
||||||
|
checkState();
|
||||||
|
writer.write("\""+name+"\"");
|
||||||
|
named = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void value(String value) throws IOException {
|
||||||
|
checkState();
|
||||||
|
writer.write("\""+Utilities.escapeJson(value)+"\"");
|
||||||
|
valued = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void value(Boolean value) throws IOException {
|
||||||
|
checkState();
|
||||||
|
if (value == null)
|
||||||
|
writer.write("null");
|
||||||
|
else if (value.booleanValue())
|
||||||
|
writer.write("true");
|
||||||
|
else
|
||||||
|
writer.write("false");
|
||||||
|
valued = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void value(BigDecimal value) throws IOException {
|
||||||
|
checkState();
|
||||||
|
if (value == null)
|
||||||
|
writer.write("null");
|
||||||
|
else
|
||||||
|
writer.write(value.toString());
|
||||||
|
valued = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void valueNum(String value) throws IOException {
|
||||||
|
checkState();
|
||||||
|
if (value == null)
|
||||||
|
writer.write("null");
|
||||||
|
else
|
||||||
|
writer.write(value);
|
||||||
|
valued = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void value(Integer value) throws IOException {
|
||||||
|
checkState();
|
||||||
|
if (value == null)
|
||||||
|
writer.write("null");
|
||||||
|
else
|
||||||
|
writer.write(value.toString());
|
||||||
|
valued = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beginArray() throws IOException {
|
||||||
|
checkState();
|
||||||
|
writer.write("[");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endArray() throws IOException {
|
||||||
|
writer.write("]");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish() throws IOException {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void link(String href) {
|
||||||
|
// not used
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -80,4 +80,9 @@ public class JsonCreatorGson implements JsonCreator {
|
||||||
// not used
|
// not used
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void valueNum(String value) throws IOException {
|
||||||
|
value(new BigDecimal(value));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue