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) {
|
||||
myDontStripVersionsFromReferencesAtPaths = (Set<String>) ((HashSet<String>) thePaths).clone();
|
||||
} else {
|
||||
myDontStripVersionsFromReferencesAtPaths = new HashSet<String>(thePaths);
|
||||
myDontStripVersionsFromReferencesAtPaths = new HashSet<>(thePaths);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -201,8 +201,10 @@ public class RuntimeResourceDefinition extends BaseRuntimeElementCompositeDefini
|
|||
* SPs with the same path the same way. This behaviour is
|
||||
* used by AuthorizationInterceptor
|
||||
*/
|
||||
String nextPath = massagePathForCompartmentSimilarity(next.getPath());
|
||||
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())) {
|
||||
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
|
||||
public synchronized IBaseResource toProfile() {
|
||||
validateSealed();
|
||||
|
|
|
@ -469,7 +469,7 @@ public abstract class BaseParser implements IParser {
|
|||
TagList tags = ResourceMetadataKeyEnum.TAG_LIST.get(theIResource);
|
||||
if (shouldAddSubsettedTag()) {
|
||||
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;
|
||||
|
@ -746,7 +746,7 @@ public abstract class BaseParser implements IParser {
|
|||
if (shouldAddSubsettedTag()) {
|
||||
IBaseCoding coding = metaValue.addTag();
|
||||
coding.setCode(Constants.TAG_SUBSETTED_CODE);
|
||||
coding.setSystem(Constants.TAG_SUBSETTED_SYSTEM);
|
||||
coding.setSystem(getSubsettedCodeSystem());
|
||||
coding.setDisplay(subsetDescription());
|
||||
}
|
||||
|
||||
|
@ -785,6 +785,14 @@ public abstract class BaseParser implements IParser {
|
|||
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
|
||||
public void setDontEncodeElements(Set<String> theDontEncodeElements) {
|
||||
myDontEncodeElementsIncludesStars = false;
|
||||
|
|
|
@ -1286,9 +1286,7 @@ class ParserState<T> {
|
|||
} else {
|
||||
try {
|
||||
myInstance.setValueAsString(theValue);
|
||||
} catch (DataFormatException e) {
|
||||
myErrorHandler.invalidValue(null, theValue, e.getMessage());
|
||||
} catch (IllegalArgumentException e) {
|
||||
} catch (DataFormatException | IllegalArgumentException e) {
|
||||
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_501_NOT_IMPLEMENTED = 501;
|
||||
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_METADATA = "metadata";
|
||||
public static final String OO_INFOSTATUS_PROCESSING = "processing";
|
||||
|
|
|
@ -89,7 +89,15 @@ public enum RestSearchParameterTypeEnum {
|
|||
*/
|
||||
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:
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
public BaseServerResponseException(int theStatusCode, Throwable theCause) {
|
||||
super(theCause.toString(), theCause);
|
||||
super(theCause.getMessage(), theCause);
|
||||
myStatusCode = theStatusCode;
|
||||
myBaseOperationOutcome = null;
|
||||
}
|
||||
|
|
|
@ -44,10 +44,23 @@ public class InvalidRequestException extends BaseServerResponseException {
|
|||
public static final int STATUS_CODE = Constants.STATUS_HTTP_400_BAD_REQUEST;
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public InvalidRequestException(String theMessage) {
|
||||
super(STATUS_CODE, theMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public InvalidRequestException(String theMessage, Throwable theCause) {
|
||||
super(STATUS_CODE, theMessage, theCause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public InvalidRequestException(Throwable 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.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
|
@ -24,6 +25,8 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
|
|||
*/
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
|
@ -40,6 +43,7 @@ import ca.uhn.fhir.parser.DataFormatException;
|
|||
|
||||
public class FhirTerser {
|
||||
|
||||
public static final Pattern COMPARTMENT_MATCHER_PATH = Pattern.compile("([a-zA-Z.]+)\\.where\\(resolve\\(\\) is ([a-zA-Z]+)\\)");
|
||||
private FhirContext myContext;
|
||||
|
||||
public FhirTerser(FhirContext theContext) {
|
||||
|
@ -364,8 +368,26 @@ public class FhirTerser {
|
|||
List<RuntimeSearchParam> params = sourceDef.getSearchParamsForCompartmentName(theCompartmentName);
|
||||
for (RuntimeSearchParam nextParam : params) {
|
||||
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)) {
|
||||
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
|
||||
|
@ -374,7 +396,7 @@ public class FhirTerser {
|
|||
*/
|
||||
if (isBlank(nextRef) && nextValue.getResource() != null) {
|
||||
IBaseResource nextTarget = nextValue.getResource();
|
||||
IIdType nextTargetId = nextTarget.getIdElement().toUnqualifiedVersionless();
|
||||
nextTargetId = nextTarget.getIdElement().toUnqualifiedVersionless();
|
||||
if (!nextTargetId.hasResourceType()) {
|
||||
String resourceType = myContext.getResourceDefinition(nextTarget).getName();
|
||||
nextTargetId.setParts(null, resourceType, nextTargetId.getIdPart(), null);
|
||||
|
@ -382,6 +404,12 @@ public class FhirTerser {
|
|||
nextRef = nextTargetId.getValue();
|
||||
}
|
||||
|
||||
if (isNotBlank(wantType)) {
|
||||
if (!nextTargetId.getResourceType().equals(wantType)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (wantRef.equals(nextRef)) {
|
||||
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.StructureDefinition;
|
||||
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.List;
|
||||
|
@ -39,7 +39,7 @@ public class LoadingValidationSupportR4 implements org.hl7.fhir.r4.hapi.ctx.IVal
|
|||
private FhirContext myCtx = FhirContext.forR4();
|
||||
|
||||
@Override
|
||||
public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
||||
public ValueSetExpander.ValueSetExpansionOutcome expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -98,9 +98,9 @@ public class VersionedApiConverterInterceptor extends InterceptorAdapter {
|
|||
IBaseResource converted = null;
|
||||
try {
|
||||
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) {
|
||||
converted = myVersionConvertor_30_40.convertResource(toR4(responseResource));
|
||||
converted = myVersionConvertor_30_40.convertResource(toR4(responseResource), true);
|
||||
} else if (wantVersion == FhirVersionEnum.DSTU2 && haveVersion == FhirVersionEnum.R4) {
|
||||
converted = myVersionConvertor_10_40.convertResource(toR4(responseResource));
|
||||
} else if (wantVersion == FhirVersionEnum.R4 && haveVersion == FhirVersionEnum.DSTU2) {
|
||||
|
|
|
@ -1,28 +1,69 @@
|
|||
package org.hl7.fhir.convertors;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR - Converter
|
||||
* %%
|
||||
* 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 VersionConvertorConstants {
|
||||
|
||||
public final static String MODIFIER_REASON_EXTENSION = "http://hl7.org/fhir/tooling/StructureDefinition/r4ModifierReason";
|
||||
public final static String MODIFIER_REASON_LEGACY = "No Modifier Reason provideed in previous versions of FHIR";
|
||||
}
|
||||
package org.hl7.fhir.convertors;
|
||||
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
||||
public class VersionConvertorConstants {
|
||||
|
||||
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";
|
||||
public final static String MODIFIER_REASON_EXTENSION = "http://hl7.org/fhir/4.0/StructureDefinition/extension-ElementDefinition.isModifierReason";
|
||||
public final static String MODIFIER_REASON_LEGACY = "No Modifier Reason provideed in previous versions of FHIR";
|
||||
|
||||
public static String refToVS(String url) {
|
||||
if (url == null)
|
||||
return null;
|
||||
if (url.equals("http://www.genenames.org"))
|
||||
return "http://hl7.org/fhir/ValueSet/genenames";
|
||||
else if (url.equals("http://varnomen.hgvs.org/"))
|
||||
return "http://hl7.org/fhir/ValueSet/variants";
|
||||
else if (url.equals("http://www.ncbi.nlm.nih.gov/nuccore?db=nuccore"))
|
||||
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"))
|
||||
return "http://hl7.org/fhir/ValueSet/clinvar";
|
||||
else if (url.equals("http://cancer.sanger.ac.uk/cancergenome/projects/cosmic/"))
|
||||
return "http://hl7.org/fhir/ValueSet/cosmic";
|
||||
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
|
||||
ParserOptions parserOptions = retVal.getParserOptions();
|
||||
parserOptions.setDontStripVersionsFromReferencesAtPaths("AuditEvent.entity.reference");
|
||||
parserOptions.setDontStripVersionsFromReferencesAtPaths("AuditEvent.entity.what");
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
|
|
@ -388,7 +388,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
|||
ResourceTable resource = myResourceTableDao.findById(theResourceId).orElseThrow(IllegalStateException::new);
|
||||
|
||||
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());
|
||||
|
||||
|
@ -2338,7 +2340,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
|||
IResource res = (IResource) theResource;
|
||||
TagList tagList = ResourceMetadataKeyEnum.TAG_LIST.get(res);
|
||||
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();
|
||||
}
|
||||
List<IdDt> profileList = ResourceMetadataKeyEnum.PROFILES.get(res);
|
||||
|
@ -2347,7 +2349,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
|||
}
|
||||
} else {
|
||||
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().getProfile().size();
|
||||
totalMetaCount += res.getMeta().getSecurity().size();
|
||||
|
|
|
@ -41,6 +41,7 @@ import java.util.regex.Pattern;
|
|||
public abstract class BaseSearchParamExtractor implements ISearchParamExtractor {
|
||||
|
||||
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);
|
||||
@Autowired
|
||||
private FhirContext myContext;
|
||||
|
|
|
@ -1186,6 +1186,10 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
BaseCodingDt id = (BaseCodingDt) theParameter;
|
||||
system = id.getSystemElement().getValueAsString();
|
||||
code = (id.getCodeElement().getValue());
|
||||
} else if (theParameter instanceof NumberParam) {
|
||||
NumberParam number = (NumberParam) theParameter;
|
||||
system = null;
|
||||
code = number.getValueAsQueryToken(myContext);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid token type: " + theParameter.getClass());
|
||||
}
|
||||
|
@ -2082,11 +2086,16 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
* SearchParameters can declare paths on multiple resources
|
||||
* types. Here we only want the ones that actually apply.
|
||||
*/
|
||||
for (Iterator<String> iter = path.iterator(); iter.hasNext(); ) {
|
||||
if (!iter.next().startsWith(theResourceType + ".")) {
|
||||
iter.remove();
|
||||
path = new ArrayList<>(path);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import org.hl7.fhir.instance.model.api.IAnyResource;
|
|||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
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.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
@ -66,7 +66,7 @@ public class JpaValidationSupportR4 implements IJpaValidationSupportR4, Applicat
|
|||
|
||||
@Override
|
||||
@Transactional(value = TxType.SUPPORTS)
|
||||
public ValueSetExpansionComponent expandValueSet(FhirContext theCtx, ConceptSetComponent theInclude) {
|
||||
public ValueSetExpander.ValueSetExpansionOutcome expandValueSet(FhirContext theCtx, ConceptSetComponent theInclude) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.dao.r4;
|
|||
* 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.
|
||||
|
@ -31,6 +31,7 @@ import com.google.common.annotations.VisibleForTesting;
|
|||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
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.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
|
@ -48,14 +49,16 @@ import javax.measure.unit.NonSI;
|
|||
import javax.measure.unit.Unit;
|
||||
import java.math.BigDecimal;
|
||||
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.isNotBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.trim;
|
||||
|
||||
public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements ISearchParamExtractor {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParamExtractorR4.class);
|
||||
|
||||
@Autowired
|
||||
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) {
|
||||
ArrayList<PathAndRef> retVal = new ArrayList<>();
|
||||
|
||||
String[] nextPathsSplit = SPLIT.split(theNextSpDef.getPath());
|
||||
String[] nextPathsSplit = SPLIT_R4.split(theNextSpDef.getPath());
|
||||
for (String path : nextPathsSplit) {
|
||||
path = path.trim();
|
||||
if (isNotBlank(path)) {
|
||||
|
||||
for (Object next : extractValues(path, theResource)) {
|
||||
retVal.add(new PathAndRef(path, next));
|
||||
}
|
||||
|
@ -447,7 +451,7 @@ public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements
|
|||
addSearchTerm(theEntity, retVal, nextSpName, value.toPlainString());
|
||||
}
|
||||
} else if (nextObject instanceof Range) {
|
||||
SimpleQuantity low = ((Range) nextObject).getLow();
|
||||
Quantity low = ((Range) nextObject).getLow();
|
||||
if (low != null) {
|
||||
BigDecimal value = low.getValue();
|
||||
if (value != null) {
|
||||
|
@ -708,9 +712,10 @@ public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements
|
|||
protected List<Object> extractValues(String thePaths, IBaseResource theResource) {
|
||||
IWorkerContext worker = new org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext(getContext(), myValidationSupport);
|
||||
FHIRPathEngine fp = new FHIRPathEngine(worker);
|
||||
fp.setHostServices(new SearchParamExtractorR4HostServices());
|
||||
|
||||
List<Object> values = new ArrayList<>();
|
||||
String[] nextPathsSplit = SPLIT.split(thePaths);
|
||||
String[] nextPathsSplit = SPLIT_R4.split(thePaths);
|
||||
for (String nextPath : nextPathsSplit) {
|
||||
List<Base> allValues;
|
||||
try {
|
||||
|
@ -748,4 +753,88 @@ public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements
|
|||
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;
|
||||
|
||||
public ResourceIndexedSearchParamQuantity() {
|
||||
// nothing
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
public ResourceIndexedSearchParamQuantity(String theParamName, BigDecimal theValue, String theSystem, String theUnits) {
|
||||
this();
|
||||
setParamName(theParamName);
|
||||
setSystem(theSystem);
|
||||
setValue(theValue);
|
||||
|
|
|
@ -39,6 +39,7 @@ import java.util.Date;
|
|||
public class ResourceLink implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
public static final int SRC_PATH_LENGTH = 200;
|
||||
|
||||
@SequenceGenerator(name = "SEQ_RESLINK_ID", sequenceName = "SEQ_RESLINK_ID")
|
||||
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_RESLINK_ID")
|
||||
|
@ -46,7 +47,7 @@ public class ResourceLink implements Serializable {
|
|||
@Column(name = "PID")
|
||||
private Long myId;
|
||||
|
||||
@Column(name = "SRC_PATH", length = 100, nullable = false)
|
||||
@Column(name = "SRC_PATH", length = SRC_PATH_LENGTH, nullable = false)
|
||||
private String mySourcePath;
|
||||
|
||||
@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.ValueSet;
|
||||
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.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
@ -142,10 +142,11 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvcImpl implements
|
|||
|
||||
|
||||
@Override
|
||||
public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
||||
public ValueSetExpander.ValueSetExpansionOutcome expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
||||
ValueSet valueSetToExpand = new ValueSet();
|
||||
valueSetToExpand.getCompose().addInclude(theInclude);
|
||||
return super.expandValueSet(valueSetToExpand).getExpansion();
|
||||
ValueSet expanded = super.expandValueSet(valueSetToExpand);
|
||||
return new ValueSetExpander.ValueSetExpansionOutcome(expanded);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -385,7 +385,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
p.addName().addFamily("Hello");
|
||||
|
||||
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);
|
||||
|
||||
try {
|
||||
|
|
|
@ -653,7 +653,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
p.addIdentifier().setSystem("urn:system").setValue("testCreateTextIdFails");
|
||||
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 {
|
||||
myPatientDao.create(p, mySrd);
|
||||
|
|
|
@ -2,7 +2,7 @@ package ca.uhn.fhir.jpa.dao.dstu3;
|
|||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
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.verify;
|
||||
|
||||
|
|
|
@ -136,6 +136,9 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
|
|||
@Autowired
|
||||
@Qualifier("myImmunizationRecommendationDaoR4")
|
||||
protected IFhirResourceDao<ImmunizationRecommendation> myImmunizationRecommendationDao;
|
||||
@Autowired
|
||||
@Qualifier("myRiskAssessmentDaoR4")
|
||||
protected IFhirResourceDao<RiskAssessment> myRiskAssessmentDao;
|
||||
protected IServerInterceptor myInterceptor;
|
||||
@Autowired
|
||||
@Qualifier("myLocationDaoR4")
|
||||
|
|
|
@ -382,7 +382,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
map.setLoadSynchronous(true);
|
||||
map.add("reason", new ReferenceParam(conditionId));
|
||||
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
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testEverythingWithLargeSet() throws Exception {
|
||||
myFhirCtx.setParserErrorHandler(new StrictErrorHandler());
|
||||
|
||||
|
@ -583,40 +584,40 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testIndexNoDuplicatesNumber() {
|
||||
final ImmunizationRecommendation res = new ImmunizationRecommendation();
|
||||
res.addRecommendation().setDoseNumber(new PositiveIntType(1));
|
||||
res.addRecommendation().setDoseNumber(new PositiveIntType(1));
|
||||
res.addRecommendation().setDoseNumber(new PositiveIntType(1));
|
||||
res.addRecommendation().setDoseNumber(new PositiveIntType(2));
|
||||
res.addRecommendation().setDoseNumber(new PositiveIntType(2));
|
||||
res.addRecommendation().setDoseNumber(new PositiveIntType(2));
|
||||
final RiskAssessment res = new RiskAssessment();
|
||||
res.addPrediction().setProbability(new DecimalType("1.0"));
|
||||
res.addPrediction().setProbability(new DecimalType("1.0"));
|
||||
res.addPrediction().setProbability(new DecimalType("1.0"));
|
||||
res.addPrediction().setProbability(new DecimalType("2.0"));
|
||||
res.addPrediction().setProbability(new DecimalType("2.0"));
|
||||
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));
|
||||
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() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus status) {
|
||||
ResourceTable resource = myResourceTableDao.findAll().iterator().next();
|
||||
assertEquals("ImmunizationRecommendation", resource.getResourceType());
|
||||
assertEquals("RiskAssessment", resource.getResourceType());
|
||||
|
||||
Class<ResourceIndexedSearchParamNumber> type = ResourceIndexedSearchParamNumber.class;
|
||||
List<ResourceIndexedSearchParamNumber> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
|
||||
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.calculateHashes();
|
||||
ResourceIndexedSearchParamNumber expect1 = new ResourceIndexedSearchParamNumber(ImmunizationRecommendation.SP_DOSE_SEQUENCE, null);
|
||||
expect1.setResource(resource).setMissing(true);
|
||||
ResourceIndexedSearchParamNumber expect1 = new ResourceIndexedSearchParamNumber(RiskAssessment.SP_PROBABILITY, new BigDecimal("2.00"));
|
||||
expect1.setResource(resource);
|
||||
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
|
||||
public void testSearchCompositeParamQuantity() {
|
||||
//@formatter:off
|
||||
Observation o1 = new Observation();
|
||||
o1.addComponent()
|
||||
.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")))
|
||||
.setValue(new Quantity().setSystem("http://bar").setCode("code2").setValue(200));
|
||||
IIdType id2 = myObservationDao.create(o2, mySrd).getId().toUnqualifiedVersionless();
|
||||
//@formatter:on
|
||||
|
||||
String param = Observation.SP_COMPONENT_CODE_VALUE_QUANTITY;
|
||||
|
||||
{
|
||||
TokenParam v0 = new TokenParam("http://foo", "code1");
|
||||
QuantityParam v1 = new QuantityParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, 150, "http://bar", "code1");
|
||||
CompositeParam<TokenParam, QuantityParam> val = new CompositeParam<TokenParam, QuantityParam>(v0, v1);
|
||||
IBundleProvider result = myObservationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(param, val));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(result), containsInAnyOrder(id2.getValue()));
|
||||
CompositeParam<TokenParam, QuantityParam> val = new CompositeParam<>(v0, v1);
|
||||
SearchParameterMap map = new SearchParameterMap().setLoadSynchronous(true).add(param, val);
|
||||
IBundleProvider result = myObservationDao.search(map);
|
||||
assertThat("Got: "+ toUnqualifiedVersionlessIdValues(result), toUnqualifiedVersionlessIdValues(result), containsInAnyOrder(id2.getValue()));
|
||||
}
|
||||
{
|
||||
TokenParam v0 = new TokenParam("http://foo", "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));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(result), containsInAnyOrder(id1.getValue(), id2.getValue()));
|
||||
}
|
||||
{
|
||||
TokenParam v0 = new TokenParam("http://foo", "code4");
|
||||
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));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(result), empty());
|
||||
}
|
||||
{
|
||||
TokenParam v0 = new TokenParam("http://foo", "code1");
|
||||
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));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(result), empty());
|
||||
}
|
||||
|
@ -1543,26 +1564,26 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testSearchNumberParam() {
|
||||
ImmunizationRecommendation e1 = new ImmunizationRecommendation();
|
||||
RiskAssessment e1 = new RiskAssessment();
|
||||
e1.addIdentifier().setSystem("foo").setValue("testSearchNumberParam01");
|
||||
e1.addRecommendation().setDoseNumber(new PositiveIntType(4 * 24 * 60));
|
||||
IIdType id1 = myImmunizationRecommendationDao.create(e1, mySrd).getId();
|
||||
e1.addPrediction().setProbability(new DecimalType(4 * 24 * 60));
|
||||
IIdType id1 = myRiskAssessmentDao.create(e1, mySrd).getId();
|
||||
|
||||
ImmunizationRecommendation e2 = new ImmunizationRecommendation();
|
||||
RiskAssessment e2 = new RiskAssessment();
|
||||
e2.addIdentifier().setSystem("foo").setValue("testSearchNumberParam02");
|
||||
e2.addRecommendation().setDoseNumber(new PositiveIntType(4));
|
||||
IIdType id2 = myImmunizationRecommendationDao.create(e2, mySrd).getId();
|
||||
e2.addPrediction().setProbability(new DecimalType(4));
|
||||
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());
|
||||
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());
|
||||
}
|
||||
{
|
||||
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());
|
||||
assertThat(toUnqualifiedVersionlessIds(found), containsInAnyOrder(id2.toUnqualifiedVersionless()));
|
||||
}
|
||||
|
@ -2619,7 +2640,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
// Irrelevant include
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
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);
|
||||
List<IBaseResource> patients = toList(search);
|
||||
assertEquals(1, patients.size());
|
||||
|
|
|
@ -35,6 +35,7 @@ import java.util.stream.Collectors;
|
|||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
|
||||
|
||||
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);
|
||||
ValidationResult result = validator.validateWithResult(theResult);
|
||||
|
||||
if (!result.isSuccessful()) {
|
||||
ourLog.info(parser.encodeResourceToString(result.toOperationOutcome()));
|
||||
fail(parser.encodeResourceToString(result.toOperationOutcome()));
|
||||
}
|
||||
assertEquals(1, result.getMessages().size());
|
||||
assertThat(result.getMessages().get(0).getMessage(), containsString("dom-6: A resource should have narrative for robust management"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1150,7 +1150,7 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
|
|||
IIdType idIn1 = myAuditEventDao.create(aeIn1, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
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();
|
||||
|
||||
AuditEvent aeOut1 = new AuditEvent();
|
||||
|
@ -1223,7 +1223,7 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
|
|||
// Now let's update
|
||||
valueSet = new ValueSet();
|
||||
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);
|
||||
myValueSetDao.update(valueSet, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
|
|
|
@ -745,7 +745,7 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
|||
p.addIdentifier().setSystem("urn:system").setValue("testCreateTextIdFails");
|
||||
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 {
|
||||
myPatientDao.create(p, mySrd);
|
||||
|
|
|
@ -721,7 +721,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
|
||||
Observation obs = new Observation();
|
||||
obs.setSubject(new Reference(ptid));
|
||||
obs.setContext(new Reference(encid));
|
||||
obs.setEncounter(new Reference(encid));
|
||||
myObservationDao.create(obs);
|
||||
|
||||
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
||||
|
|
|
@ -131,7 +131,7 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
|
|||
input.getMeta().getProfile().add(new CanonicalType(sd.getUrl()));
|
||||
|
||||
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.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.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.getCode().addCoding().setSystem("http://loinc.org").setCode("12345");
|
||||
|
||||
|
|
|
@ -228,15 +228,17 @@ public class FhirResourceDaoR4ValueSetTest extends BaseJpaR4Test {
|
|||
IPrimitiveType<String> display = null;
|
||||
Coding coding = null;
|
||||
CodeableConcept codeableConcept = null;
|
||||
StringType vsIdentifier = new StringType("http://hl7.org/fhir/ValueSet/v2-0487");
|
||||
StringType code = new StringType("BRN");
|
||||
StringType system = new StringType("http://hl7.org/fhir/v2/0487");
|
||||
StringType vsIdentifier = new StringType("http://hl7.org/fhir/ValueSet/yesnodontknow");
|
||||
StringType code = new StringType("Y");
|
||||
StringType system = new StringType("http://terminology.hl7.org/CodeSystem/v2-0136");
|
||||
ValidateCodeResult result = myValueSetDao.validateCode(vsIdentifier, null, code, system, display, coding, codeableConcept, mySrd);
|
||||
|
||||
ourLog.info(result.getMessage());
|
||||
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.jpa.dao.DaoConfig;
|
||||
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.ResourceIndexedSearchParamQuantity;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamToken;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.search.JpaRuntimeSearchParam;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport;
|
||||
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.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
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 {
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(SearchParamExtractorR4Test.class);
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static IValidationSupport ourValidationSupport;
|
||||
private ISearchParamRegistry mySearchParamRegistry;
|
||||
|
||||
@Test
|
||||
public void testParamWithOrInPath() {
|
||||
Observation obs = new Observation();
|
||||
obs.addCategory().addCoding().setSystem("SYSTEM").setCode("CODE");
|
||||
|
||||
ISearchParamRegistry searchParamRegistry = new ISearchParamRegistry() {
|
||||
@Before
|
||||
public void before() {
|
||||
mySearchParamRegistry = new ISearchParamRegistry() {
|
||||
@Override
|
||||
public void forceRefresh() {
|
||||
// nothing
|
||||
|
@ -42,7 +48,7 @@ public class SearchParamExtractorR4Test {
|
|||
|
||||
@Override
|
||||
public RuntimeSearchParam getActiveSearchParam(String theResourceName, String theParamName) {
|
||||
throw new UnsupportedOperationException();
|
||||
return getActiveSearchParams(theResourceName).get(theParamName);
|
||||
}
|
||||
|
||||
@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);
|
||||
assertEquals(1, tokens.size());
|
||||
ResourceIndexedSearchParamToken token = (ResourceIndexedSearchParamToken) tokens.iterator().next();
|
||||
|
@ -90,6 +103,50 @@ public class SearchParamExtractorR4Test {
|
|||
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
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
|
|
|
@ -34,7 +34,7 @@ import java.nio.charset.StandardCharsets;
|
|||
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
|
|
|
@ -39,7 +39,7 @@ import java.nio.charset.StandardCharsets;
|
|||
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@TestPropertySource(properties = {
|
||||
|
|
|
@ -23,6 +23,7 @@ import ca.uhn.fhir.parser.StrictErrorHandler;
|
|||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
public class PatientEverythingR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
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)
|
||||
.named("lookup")
|
||||
.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();
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
|
@ -245,7 +245,7 @@ public class ResourceProviderR4CodeSystemTest extends BaseResourceProviderR4Test
|
|||
.onType(CodeSystem.class)
|
||||
.named("lookup")
|
||||
.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();
|
||||
//@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.IIdType;
|
||||
import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator;
|
||||
import org.hl7.fhir.r4.model.AuditEvent;
|
||||
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.*;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleLinkComponent;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleType;
|
||||
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
|
||||
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.EncounterStatus;
|
||||
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.Observation;
|
||||
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.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.SubscriptionStatus;
|
||||
import org.hl7.fhir.r4.model.UnsignedIntType;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
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.UrlUtil;
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
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();
|
||||
|
||||
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();
|
||||
|
||||
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));
|
||||
IIdType e1id = ourClient.create().resource(e1).execute().getId();
|
||||
|
||||
//@formatter:off
|
||||
Bundle res = ourClient.search()
|
||||
.forResource(Encounter.class)
|
||||
.where(Encounter.IDENTIFIER.exactly().systemAndCode("urn:foo", "testDeepChainingE1"))
|
||||
|
@ -755,7 +712,8 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
.include(Location.INCLUDE_PARTOF.asRecursive())
|
||||
.returnBundle(Bundle.class)
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(res));
|
||||
|
||||
assertEquals(3, res.getEntry().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
|
||||
public void testDeleteConditionalMultiple() {
|
||||
String methodName = "testDeleteConditionalMultiple";
|
||||
|
@ -830,16 +827,13 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
String methodName = "testDeleteConditionalNoMatches";
|
||||
|
||||
HttpDelete delete = new HttpDelete(ourServerBase + "/Patient?identifier=" + methodName);
|
||||
CloseableHttpResponse resp = ourHttpClient.execute(delete);
|
||||
try {
|
||||
try (CloseableHttpResponse resp = ourHttpClient.execute(delete)) {
|
||||
ourLog.info(resp.toString());
|
||||
String response = IOUtils.toString(resp.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(response);
|
||||
assertEquals(200, resp.getStatusLine().getStatusCode());
|
||||
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>"));
|
||||
} finally {
|
||||
IOUtils.closeQuietly(resp);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -847,14 +841,11 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
@Test
|
||||
public void testDeleteInvalidReference() throws IOException {
|
||||
HttpDelete delete = new HttpDelete(ourServerBase + "/Patient");
|
||||
CloseableHttpResponse response = ourHttpClient.execute(delete);
|
||||
try {
|
||||
try (CloseableHttpResponse response = ourHttpClient.execute(delete)) {
|
||||
String responseString = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseString);
|
||||
assertEquals(400, response.getStatusLine().getStatusCode());
|
||||
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();
|
||||
|
||||
Device dev = new Device();
|
||||
dev.setModel(methodName);
|
||||
dev.setManufacturer(methodName);
|
||||
dev.getOwner().setReferenceElement(orgId2);
|
||||
IIdType devId = ourClient.create().resource(dev).execute().getId().toUnqualifiedVersionless();
|
||||
|
||||
|
@ -1122,7 +1113,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
Observation obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(patientId);
|
||||
obs.getDevice().setReferenceElement(devId);
|
||||
obs.getContext().setReferenceElement(encId);
|
||||
obs.getEncounter().setReferenceElement(encId);
|
||||
IIdType obsId = ourClient.create().resource(obs).execute().getId().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();
|
||||
|
||||
Device dev = new Device();
|
||||
dev.setModel(methodName);
|
||||
dev.setManufacturer(methodName);
|
||||
dev.getOwner().setReferenceElement(orgId2);
|
||||
IIdType devId = ourClient.create().resource(dev).execute().getId().toUnqualifiedVersionless();
|
||||
|
||||
|
@ -1185,7 +1176,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
Observation obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(patientId);
|
||||
obs.getDevice().setReferenceElement(devId);
|
||||
obs.getContext().setReferenceElement(encId);
|
||||
obs.getEncounter().setReferenceElement(encId);
|
||||
IIdType obsId = ourClient.create().resource(obs).execute().getId().toUnqualifiedVersionless();
|
||||
|
||||
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();
|
||||
|
||||
Device dev = new Device();
|
||||
dev.setModel(methodName);
|
||||
dev.setManufacturer(methodName);
|
||||
dev.getOwner().setReferenceElement(orgId2);
|
||||
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
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testEverythingWithLargeSet() throws Exception {
|
||||
|
||||
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(1, ((Patient) history.getEntry().get(2).getResource()).getName().size());
|
||||
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(history));
|
||||
|
||||
try {
|
||||
myBundleDao.validate(history, null, null, null, null, null, mySrd);
|
||||
} catch (PreconditionFailedException e) {
|
||||
|
@ -2537,7 +2531,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
assertEquals("1", patientId.getVersionIdPart());
|
||||
|
||||
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();
|
||||
assertEquals("1", aeId.getVersionIdPart());
|
||||
|
||||
|
@ -2546,8 +2540,8 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
assertFalse(patient.getManagingOrganization().getReferenceElement().hasVersionIdPart());
|
||||
|
||||
ae = ourClient.read().resource(AuditEvent.class).withId(aeId).execute();
|
||||
assertTrue(ae.getEntityFirstRep().getReference().getReferenceElement().hasIdPart());
|
||||
assertTrue(ae.getEntityFirstRep().getReference().getReferenceElement().hasVersionIdPart());
|
||||
assertTrue(ae.getEntityFirstRep().getWhat().getReferenceElement().hasIdPart());
|
||||
assertTrue(ae.getEntityFirstRep().getWhat().getReferenceElement().hasVersionIdPart());
|
||||
|
||||
}
|
||||
|
||||
|
@ -3740,8 +3734,8 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
try {
|
||||
ourClient
|
||||
.search()
|
||||
.forResource(ImmunizationRecommendation.class)
|
||||
.where(ImmunizationRecommendation.DOSE_NUMBER.withPrefix(ParamPrefixEnum.ENDS_BEFORE).number(100))
|
||||
.forResource(Sequence.class)
|
||||
.where(Sequence.END.withPrefix(ParamPrefixEnum.ENDS_BEFORE).number(100))
|
||||
.prettyPrint()
|
||||
.returnBundle(Bundle.class)
|
||||
.execute();
|
||||
|
|
|
@ -114,7 +114,7 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
|
|||
myLocalVs = new ValueSet();
|
||||
myLocalVs.setUrl(URL_MY_VALUE_SET);
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -505,9 +505,9 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
|
|||
.operation()
|
||||
.onType(ValueSet.class)
|
||||
.named("validate-code")
|
||||
.withParameter(Parameters.class, "code", new StringType("BRN"))
|
||||
.andParameter("url", new StringType("http://hl7.org/fhir/ValueSet/v2-0487"))
|
||||
.andParameter("system", new StringType("http://hl7.org/fhir/v2/0487"))
|
||||
.withParameter(Parameters.class, "code", new StringType("Y"))
|
||||
.andParameter("url", new StringType("http://hl7.org/fhir/ValueSet/yesnodontknow"))
|
||||
.andParameter("system", new StringType("http://terminology.hl7.org/CodeSystem/v2-0136"))
|
||||
.useHttpGet()
|
||||
.execute();
|
||||
|
||||
|
@ -521,7 +521,7 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
|
|||
assertThat(((StringType) respParam.getParameter().get(1).getValue()).getValue(), containsStringIgnoringCase("succeeded"));
|
||||
|
||||
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
|
||||
|
|
|
@ -101,7 +101,7 @@ public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Tes
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testUploadMissingPackage() throws Exception {
|
||||
public void testUploadMissingPackage() {
|
||||
//@formatter:off
|
||||
try {
|
||||
ourClient
|
||||
|
|
|
@ -42,10 +42,10 @@ import javax.persistence.EntityManager;
|
|||
import java.util.*;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyBoolean;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Matchers.same;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.same;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
|
|
|
@ -95,9 +95,9 @@ public class RestHookWithEventDefinitionR4Test extends BaseResourceProviderR4Tes
|
|||
.setPurpose("Monitor all admissions to Emergency")
|
||||
.setTrigger(new TriggerDefinition()
|
||||
.setType(TriggerDefinition.TriggerType.DATAADDED)
|
||||
.setCondition(new TriggerDefinition.TriggerDefinitionConditionComponent()
|
||||
.setCondition(new Expression()
|
||||
.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()")
|
||||
)
|
||||
);
|
||||
|
|
|
@ -2043,8 +2043,6 @@
|
|||
<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-->
|
||||
</meta>
|
||||
<clinicalStatus value="active"/>
|
||||
<verificationStatus value="confirmed"/>
|
||||
<category>
|
||||
<coding>
|
||||
<system value="http://snomed.info/sct"/>
|
||||
|
@ -2116,8 +2114,6 @@
|
|||
<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-->
|
||||
</meta>
|
||||
<clinicalStatus value="active"/>
|
||||
<verificationStatus value="confirmed"/>
|
||||
<category>
|
||||
<coding>
|
||||
<system value="http://hl7.org/fhir/v3/ActCode"/>
|
||||
|
|
|
@ -348,17 +348,17 @@
|
|||
<item>
|
||||
<linkId value="1.1"/>
|
||||
<type value="choice"/>
|
||||
<options value="#verbal"/>
|
||||
<answerValueSet value="#verbal"/>
|
||||
</item>
|
||||
<item>
|
||||
<linkId value="1.2"/>
|
||||
<type value="choice"/>
|
||||
<options value="#motor"/>
|
||||
<answerValueSet value="#motor"/>
|
||||
</item>
|
||||
<item>
|
||||
<linkId value="1.3"/>
|
||||
<type value="choice"/>
|
||||
<options value="#eye"/>
|
||||
<answerValueSet value="#eye"/>
|
||||
</item>
|
||||
</Questionnaire>
|
||||
</resource>
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
},
|
||||
"id": "cf-1505178568463",
|
||||
"subject": {"reference": "Patient/2344"},
|
||||
"clinicalStatus": "active",
|
||||
"code": {"coding": [{
|
||||
"system": "http://snomed.info/sct",
|
||||
"code": "170631002",
|
||||
|
|
|
@ -69,7 +69,6 @@
|
|||
}
|
||||
}
|
||||
],
|
||||
"created" : "2005-12-24T09:35:00+11:00",
|
||||
"status" : "current",
|
||||
"description" : "Physical",
|
||||
"context" : {
|
||||
|
|
|
@ -261,7 +261,7 @@
|
|||
"subject": {
|
||||
"reference": "urn:uuid:09a8d22c-1e23-4e5f-b3bf-505772f123d1"
|
||||
},
|
||||
"context": {
|
||||
"encounter": {
|
||||
"reference": "urn:uuid:29e3a213-0df4-41e0-88f8-e3be83277022"
|
||||
},
|
||||
"effectiveDateTime": "2011-12-01T09:49:00-05:00",
|
||||
|
@ -289,7 +289,7 @@
|
|||
"subject": {
|
||||
"reference": "urn:uuid:09a8d22c-1e23-4e5f-b3bf-505772f123d1"
|
||||
},
|
||||
"context": {
|
||||
"encounter": {
|
||||
"reference": "urn:uuid:29e3a213-0df4-41e0-88f8-e3be83277022"
|
||||
},
|
||||
"effectiveDateTime": "2011-12-01T09:49:00-05:00",
|
||||
|
@ -317,7 +317,7 @@
|
|||
"subject": {
|
||||
"reference": "urn:uuid:09a8d22c-1e23-4e5f-b3bf-505772f123d1"
|
||||
},
|
||||
"context": {
|
||||
"encounter": {
|
||||
"reference": "urn:uuid:29e3a213-0df4-41e0-88f8-e3be83277022"
|
||||
},
|
||||
"effectiveDateTime": "2011-12-01T09:49:00-05:00",
|
||||
|
@ -345,7 +345,7 @@
|
|||
"subject": {
|
||||
"reference": "urn:uuid:09a8d22c-1e23-4e5f-b3bf-505772f123d1"
|
||||
},
|
||||
"context": {
|
||||
"encounter": {
|
||||
"reference": "urn:uuid:29e3a213-0df4-41e0-88f8-e3be83277022"
|
||||
},
|
||||
"effectiveDateTime": "2011-12-01T10:57:00-05:00",
|
||||
|
|
|
@ -131,7 +131,7 @@
|
|||
"binding": {
|
||||
"strength": "example",
|
||||
"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": [
|
||||
{
|
||||
|
|
|
@ -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.BaseTableTask;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -126,6 +127,11 @@ public class JdbcUtils {
|
|||
return BaseTableColumnTypeTask.ColumnTypeEnum.STRING.getDescriptor(length);
|
||||
case Types.BIGINT:
|
||||
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:
|
||||
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
|
||||
*/
|
||||
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.MARIADB_10_1, "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");
|
||||
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);
|
||||
|
||||
}
|
||||
|
|
|
@ -37,7 +37,22 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
|||
* Constructor
|
||||
*/
|
||||
public HapiFhirJpaMigrationTasks() {
|
||||
init340();
|
||||
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() {
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
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 static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class AddColumnTest extends BaseTest {
|
||||
|
@ -26,6 +27,23 @@ public class AddColumnTest extends BaseTest {
|
|||
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
|
||||
public void testColumnAlreadyExists() throws SQLException {
|
||||
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.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
|
||||
retVal.setFetchSizeDefaultMaximum(10000);
|
||||
retVal.setReindexThreadCount(1);
|
||||
retVal.setExpungeEnabled(true);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ public class TestR4Config extends BaseJavaConfigR4 {
|
|||
retVal.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
|
||||
retVal.setCountSearchResultsUpTo(TestR4Config.COUNT_SEARCH_RESULTS_UP_TO);
|
||||
retVal.setFetchSizeDefaultMaximum(10000);
|
||||
retVal.setExpungeEnabled(true);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhirtest.interceptor;
|
|||
|
||||
import ca.uhn.fhir.jpa.provider.BaseJpaSystemProvider;
|
||||
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.server.exceptions.ForbiddenOperationException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor;
|
||||
|
@ -35,6 +36,9 @@ public class PublicSecurityInterceptor extends AuthorizationInterceptor {
|
|||
return new RuleBuilder()
|
||||
.deny().operation().named(BaseJpaSystemProvider.MARK_ALL_RESOURCES_FOR_REINDEXING).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()
|
||||
.build();
|
||||
}
|
||||
|
|
|
@ -644,9 +644,11 @@ public class RestfulServerUtils {
|
|||
|
||||
if (theServer.getETagSupport() == ETagSupportEnum.ENABLED) {
|
||||
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())) {
|
||||
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);
|
||||
}
|
||||
|
||||
public static String createEtag(String theVersionId) {
|
||||
return "W/\"" + theVersionId + '"';
|
||||
}
|
||||
|
||||
public static Integer tryToExtractNamedParameter(RequestDetails theRequest, String theParamName) {
|
||||
String[] retVal = theRequest.getParameters().get(theParamName);
|
||||
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.BundleEntryParts;
|
||||
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.ToStringStyle;
|
||||
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.IIdType;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -376,7 +375,7 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
|
|||
String compartmentOwnerResourceType = next.getResourceType();
|
||||
if (!StringUtils.equals(appliesToResourceType, 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
|
||||
|
|
|
@ -96,6 +96,12 @@ public class SearchParameter extends BaseQueryParameter {
|
|||
ourParamTypes.put(HasParam.class, RestSearchParameterTypeEnum.HAS);
|
||||
ourParamTypes.put(HasOrListParam.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();
|
||||
|
|
|
@ -802,7 +802,7 @@ public class JsonParserDstu2_1Test {
|
|||
ourLog.info(encoded);
|
||||
|
||||
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("THE DIV")));
|
||||
assertThat(encoded, containsString("family"));
|
||||
|
@ -836,7 +836,7 @@ public class JsonParserDstu2_1Test {
|
|||
ourLog.info(encoded);
|
||||
|
||||
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, containsString("family"));
|
||||
assertThat(encoded, not(containsString("maritalStatus")));
|
||||
|
@ -856,7 +856,7 @@ public class JsonParserDstu2_1Test {
|
|||
ourLog.info(encoded);
|
||||
|
||||
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 + "\""));
|
||||
assertThat(encoded, not(containsString("THE DIV")));
|
||||
assertThat(encoded, containsString("family"));
|
||||
|
|
|
@ -1362,7 +1362,7 @@ public class XmlParserDstu2_1Test {
|
|||
ourLog.info(encoded);
|
||||
|
||||
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("THE DIV")));
|
||||
assertThat(encoded, containsString("family"));
|
||||
|
@ -1462,7 +1462,7 @@ public class XmlParserDstu2_1Test {
|
|||
ourLog.info(encoded);
|
||||
|
||||
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, containsString("family"));
|
||||
assertThat(encoded, not(containsString("maritalStatus")));
|
||||
|
@ -1483,7 +1483,7 @@ public class XmlParserDstu2_1Test {
|
|||
|
||||
assertThat(encoded, containsString("<Patient"));
|
||||
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, containsString("family"));
|
||||
assertThat(encoded, not(containsString("maritalStatus")));
|
||||
|
|
|
@ -478,7 +478,7 @@ public class GenericClientDstu2_1Test {
|
|||
client.read().resource(Patient.class).withId("1").execute();
|
||||
fail();
|
||||
} catch (FhirClientConnectionException e) {
|
||||
assertEquals("java.lang.IllegalStateException", e.getMessage());
|
||||
assertEquals(null, e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
@ -808,7 +808,7 @@ public class JsonParserDstu2Test {
|
|||
ourLog.info(encoded);
|
||||
|
||||
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("THE DIV")));
|
||||
assertThat(encoded, containsString("family"));
|
||||
|
@ -918,7 +918,7 @@ public class JsonParserDstu2Test {
|
|||
ourLog.info(encoded);
|
||||
|
||||
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, containsString("family"));
|
||||
assertThat(encoded, not(containsString("maritalStatus")));
|
||||
|
@ -940,7 +940,7 @@ public class JsonParserDstu2Test {
|
|||
ourLog.info(encoded);
|
||||
|
||||
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 + "\","));
|
||||
assertThat(encoded, not(containsString("THE DIV")));
|
||||
assertThat(encoded, containsString("family"));
|
||||
|
|
|
@ -22,7 +22,6 @@ import org.junit.Before;
|
|||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import org.mockito.Matchers;
|
||||
import org.mockito.internal.stubbing.answers.ThrowsException;
|
||||
import org.xmlunit.builder.DiffBuilder;
|
||||
import org.xmlunit.builder.Input;
|
||||
|
@ -1544,7 +1543,7 @@ public class XmlParserDstu2Test {
|
|||
ourLog.info(encoded);
|
||||
|
||||
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("THE DIV")));
|
||||
assertThat(encoded, containsString("family"));
|
||||
|
@ -1658,7 +1657,7 @@ public class XmlParserDstu2Test {
|
|||
ourLog.info(encoded);
|
||||
|
||||
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, containsString("family"));
|
||||
assertThat(encoded, not(containsString("maritalStatus")));
|
||||
|
@ -1681,7 +1680,7 @@ public class XmlParserDstu2Test {
|
|||
|
||||
assertThat(encoded, containsString("<Patient"));
|
||||
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, containsString("family"));
|
||||
assertThat(encoded, not(containsString("maritalStatus")));
|
||||
|
|
|
@ -195,7 +195,9 @@ public interface IWorkerContext {
|
|||
* @throws FHIRException
|
||||
*/
|
||||
public ValueSetExpansionComponent expandVS(ConceptSetComponent inc, boolean heiarchical) throws TerminologyServiceException;
|
||||
|
||||
|
||||
StructureDefinition fetchTypeDefinition(String theCode);
|
||||
|
||||
public class ValidationResult {
|
||||
private ConceptDefinitionComponent definition;
|
||||
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.utils.INarrativeGenerator;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
|
||||
import java.util.*;
|
||||
|
@ -69,6 +70,8 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander
|
|||
vso = getExpander().expand(theSource, theProfile);
|
||||
} catch (InvalidRequestException e) {
|
||||
throw e;
|
||||
} catch (TerminologyServiceException e) {
|
||||
throw new InvalidRequestException(e.getMessage(), e);
|
||||
} catch (Exception e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
|
@ -89,6 +92,11 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander
|
|||
return myValidationSupport.expandValueSet(myCtx, theInc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StructureDefinition fetchTypeDefinition(String theCode) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(String theSystem) {
|
||||
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
|
||||
|
|
|
@ -1,465 +1,461 @@
|
|||
package org.hl7.fhir.dstu3.terminologies;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
||||
/*
|
||||
* 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.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
import org.hl7.fhir.dstu3.context.IWorkerContext;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionDesignationComponent;
|
||||
import org.hl7.fhir.dstu3.model.DateTimeType;
|
||||
import org.hl7.fhir.dstu3.model.ExpansionProfile;
|
||||
import org.hl7.fhir.dstu3.model.Factory;
|
||||
import org.hl7.fhir.dstu3.model.PrimitiveType;
|
||||
import org.hl7.fhir.dstu3.model.Type;
|
||||
import org.hl7.fhir.dstu3.model.UriType;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptReferenceComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptReferenceDesignationComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetFilterComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.FilterOperator;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetComposeComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionParameterComponent;
|
||||
import org.hl7.fhir.dstu3.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.exceptions.NoTerminologyServiceException;
|
||||
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
||||
public class ValueSetExpanderSimple implements ValueSetExpander {
|
||||
|
||||
private List<ValueSetExpansionContainsComponent> codes = new ArrayList<ValueSet.ValueSetExpansionContainsComponent>();
|
||||
private List<ValueSetExpansionContainsComponent> roots = new ArrayList<ValueSet.ValueSetExpansionContainsComponent>();
|
||||
private Map<String, ValueSetExpansionContainsComponent> map = new HashMap<String, ValueSet.ValueSetExpansionContainsComponent>();
|
||||
private IWorkerContext context;
|
||||
private boolean canBeHeirarchy = true;
|
||||
private Set<String> excludeKeys = new HashSet<String>();
|
||||
private Set<String> excludeSystems = new HashSet<String>();
|
||||
private ValueSetExpanderFactory factory;
|
||||
private ValueSet focus;
|
||||
private int maxExpansionSize = 500;
|
||||
|
||||
private int total;
|
||||
|
||||
public ValueSetExpanderSimple(IWorkerContext context, ValueSetExpanderFactory factory) {
|
||||
super();
|
||||
this.context = context;
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
public void setMaxExpansionSize(int theMaxExpansionSize) {
|
||||
maxExpansionSize = theMaxExpansionSize;
|
||||
}
|
||||
|
||||
private ValueSetExpansionContainsComponent addCode(String system, String code, String display, ValueSetExpansionContainsComponent parent, List<ConceptDefinitionDesignationComponent> designations,
|
||||
ExpansionProfile profile, boolean isAbstract, boolean inactive, List<ValueSet> filters) {
|
||||
if (filters != null && !filters.isEmpty() && !filterContainsCode(filters, system, code))
|
||||
return null;
|
||||
ValueSetExpansionContainsComponent n = new ValueSet.ValueSetExpansionContainsComponent();
|
||||
n.setSystem(system);
|
||||
n.setCode(code);
|
||||
if (isAbstract)
|
||||
n.setAbstract(true);
|
||||
if (inactive)
|
||||
n.setInactive(true);
|
||||
|
||||
if (profile.getIncludeDesignations() && designations != null) {
|
||||
for (ConceptDefinitionDesignationComponent t : designations) {
|
||||
ToolingExtensions.addLanguageTranslation(n, t.getLanguage(), t.getValue());
|
||||
}
|
||||
}
|
||||
ConceptDefinitionDesignationComponent t = profile.hasLanguage() ? getMatchingLang(designations, profile.getLanguage()) : null;
|
||||
if (t == null)
|
||||
n.setDisplay(display);
|
||||
else
|
||||
n.setDisplay(t.getValue());
|
||||
|
||||
String s = key(n);
|
||||
if (map.containsKey(s) || excludeKeys.contains(s)) {
|
||||
canBeHeirarchy = false;
|
||||
} else {
|
||||
codes.add(n);
|
||||
map.put(s, n);
|
||||
total++;
|
||||
}
|
||||
if (canBeHeirarchy && parent != null) {
|
||||
parent.getContains().add(n);
|
||||
} else {
|
||||
roots.add(n);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
private boolean filterContainsCode(List<ValueSet> filters, String system, String code) {
|
||||
for (ValueSet vse : filters)
|
||||
if (expansionContainsCode(vse.getExpansion().getContains(), system, code))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean expansionContainsCode(List<ValueSetExpansionContainsComponent> contains, String system, String code) {
|
||||
for (ValueSetExpansionContainsComponent cc : contains) {
|
||||
if (system.equals(cc.getSystem()) && code.equals(cc.getCode()))
|
||||
return true;
|
||||
if (expansionContainsCode(cc.getContains(), system, code))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private ConceptDefinitionDesignationComponent getMatchingLang(List<ConceptDefinitionDesignationComponent> list, String lang) {
|
||||
for (ConceptDefinitionDesignationComponent t : list)
|
||||
if (t.getLanguage().equals(lang))
|
||||
return t;
|
||||
for (ConceptDefinitionDesignationComponent t : list)
|
||||
if (t.getLanguage().startsWith(lang))
|
||||
return t;
|
||||
return null;
|
||||
}
|
||||
|
||||
private void addCodeAndDescendents(CodeSystem cs, String system, ConceptDefinitionComponent def, ValueSetExpansionContainsComponent parent, ExpansionProfile profile, List<ValueSet> filters)
|
||||
throws FHIRException {
|
||||
if (!CodeSystemUtilities.isDeprecated(cs, def)) {
|
||||
ValueSetExpansionContainsComponent np = null;
|
||||
boolean abs = CodeSystemUtilities.isNotSelectable(cs, def);
|
||||
boolean inc = CodeSystemUtilities.isInactive(cs, def);
|
||||
if (canBeHeirarchy || !abs)
|
||||
np = addCode(system, def.getCode(), def.getDisplay(), parent, def.getDesignation(), profile, abs, inc, filters);
|
||||
for (ConceptDefinitionComponent c : def.getConcept())
|
||||
addCodeAndDescendents(cs, system, c, np, profile, filters);
|
||||
} else
|
||||
for (ConceptDefinitionComponent c : def.getConcept())
|
||||
addCodeAndDescendents(cs, system, c, null, profile, filters);
|
||||
|
||||
}
|
||||
|
||||
private void addCodes(ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile, List<ValueSet> filters) throws ETooCostly {
|
||||
if (expand.getContains().size() > maxExpansionSize)
|
||||
throw new ETooCostly("Too many codes to display (>" + Integer.toString(expand.getContains().size()) + ")");
|
||||
for (ValueSetExpansionParameterComponent p : expand.getParameter()) {
|
||||
if (!existsInParams(params, p.getName(), p.getValue()))
|
||||
params.add(p);
|
||||
}
|
||||
|
||||
copyImportContains(expand.getContains(), null, profile, filters);
|
||||
}
|
||||
|
||||
private void excludeCode(String theSystem, String theCode) {
|
||||
ValueSetExpansionContainsComponent n = new ValueSet.ValueSetExpansionContainsComponent();
|
||||
n.setSystem(theSystem);
|
||||
n.setCode(theCode);
|
||||
String s = key(n);
|
||||
excludeKeys.add(s);
|
||||
}
|
||||
|
||||
private void excludeCodes(ConceptSetComponent exc, List<ValueSetExpansionParameterComponent> params) throws TerminologyServiceException {
|
||||
if (exc.hasSystem() && exc.getConcept().size() == 0 && exc.getFilter().size() == 0) {
|
||||
excludeSystems.add(exc.getSystem());
|
||||
}
|
||||
|
||||
if (exc.hasValueSet())
|
||||
throw new Error("Processing Value set references in exclude is not yet done");
|
||||
// importValueSet(imp.getValue(), params, profile);
|
||||
|
||||
CodeSystem cs = context.fetchCodeSystem(exc.getSystem());
|
||||
if ((cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) && context.supportsSystem(exc.getSystem())) {
|
||||
excludeCodes(context.expandVS(exc, false), params);
|
||||
return;
|
||||
}
|
||||
|
||||
for (ConceptReferenceComponent c : exc.getConcept()) {
|
||||
excludeCode(exc.getSystem(), c.getCode());
|
||||
}
|
||||
|
||||
if (exc.getFilter().size() > 0)
|
||||
throw new NotImplementedException("not done yet");
|
||||
}
|
||||
|
||||
private void excludeCodes(ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params) {
|
||||
for (ValueSetExpansionContainsComponent c : expand.getContains()) {
|
||||
excludeCode(c.getSystem(), c.getCode());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean existsInParams(List<ValueSetExpansionParameterComponent> params, String name, Type value) {
|
||||
for (ValueSetExpansionParameterComponent p : params) {
|
||||
if (p.getName().equals(name) && PrimitiveType.compareDeep(p.getValue(), value, false))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSetExpansionOutcome expand(ValueSet source, ExpansionProfile profile) {
|
||||
|
||||
if (profile == null)
|
||||
profile = makeDefaultExpansion();
|
||||
try {
|
||||
focus = source.copy();
|
||||
focus.setExpansion(new ValueSet.ValueSetExpansionComponent());
|
||||
focus.getExpansion().setTimestampElement(DateTimeType.now());
|
||||
focus.getExpansion().setIdentifier(Factory.createUUID());
|
||||
if (!profile.getUrl().startsWith("urn:uuid:"))
|
||||
focus.getExpansion().addParameter().setName("profile").setValue(new UriType(profile.getUrl()));
|
||||
|
||||
if (source.hasCompose())
|
||||
handleCompose(source.getCompose(), focus.getExpansion().getParameter(), profile);
|
||||
|
||||
if (canBeHeirarchy) {
|
||||
for (ValueSetExpansionContainsComponent c : roots) {
|
||||
focus.getExpansion().getContains().add(c);
|
||||
}
|
||||
} else {
|
||||
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
|
||||
focus.getExpansion().getContains().add(c);
|
||||
c.getContains().clear(); // make sure any heirarchy is wiped
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (total > 0) {
|
||||
focus.getExpansion().setTotal(total);
|
||||
}
|
||||
|
||||
return new ValueSetExpansionOutcome(focus);
|
||||
} catch (RuntimeException e) {
|
||||
// TODO: we should put something more specific instead of just Exception below, since
|
||||
// it swallows bugs.. what would be expected to be caught there?
|
||||
throw e;
|
||||
} catch (NoTerminologyServiceException 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.NOSERVICE);
|
||||
} 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);
|
||||
res.setIncludeDesignations(false);
|
||||
return res;
|
||||
}
|
||||
|
||||
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());
|
||||
return def.getDisplay();
|
||||
}
|
||||
|
||||
private ConceptDefinitionComponent getConceptForCode(List<ConceptDefinitionComponent> clist, String code) {
|
||||
for (ConceptDefinitionComponent c : clist) {
|
||||
if (code.equals(c.getCode()))
|
||||
return c;
|
||||
ConceptDefinitionComponent v = getConceptForCode(c.getConcept(), code);
|
||||
if (v != null)
|
||||
return v;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void handleCompose(ValueSetComposeComponent compose, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile)
|
||||
throws ETooCostly, FileNotFoundException, IOException, FHIRException {
|
||||
// Exclude comes first because we build up a map of things to exclude
|
||||
for (ConceptSetComponent inc : compose.getExclude())
|
||||
excludeCodes(inc, params);
|
||||
canBeHeirarchy = !profile.getExcludeNested() && excludeKeys.isEmpty() && excludeSystems.isEmpty();
|
||||
boolean first = true;
|
||||
for (ConceptSetComponent inc : compose.getInclude()) {
|
||||
if (first == true)
|
||||
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");
|
||||
ValueSet vs = context.fetchResource(ValueSet.class, value);
|
||||
if (vs == null)
|
||||
throw new TerminologyServiceException("Unable to find imported value set " + value);
|
||||
ValueSetExpansionOutcome vso = factory.getExpander().expand(vs, profile);
|
||||
if (vso.getError() != null)
|
||||
throw new TerminologyServiceException("Unable to expand imported value set: " + vso.getError());
|
||||
if (vso.getService() != null)
|
||||
throw new TerminologyServiceException("Unable to expand imported value set " + value);
|
||||
if (vs.hasVersion())
|
||||
if (!existsInParams(params, "version", new UriType(vs.getUrl() + "|" + vs.getVersion())))
|
||||
params.add(new ValueSetExpansionParameterComponent().setName("version").setValue(new UriType(vs.getUrl() + "|" + vs.getVersion())));
|
||||
for (ValueSetExpansionParameterComponent p : vso.getValueset().getExpansion().getParameter()) {
|
||||
if (!existsInParams(params, p.getName(), p.getValue()))
|
||||
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
|
||||
return vso.getValueset();
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
if (!inc.hasSystem()) {
|
||||
if (imports.isEmpty()) // though this is not supposed to be the case
|
||||
return;
|
||||
ValueSet base = imports.get(0);
|
||||
imports.remove(0);
|
||||
copyImportContains(base.getExpansion().getContains(), null, profile, imports);
|
||||
} else {
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cs == null) {
|
||||
if (context.isNoTerminologyServer())
|
||||
throw new NoTerminologyServiceException("unable to find code system " + inc.getSystem().toString());
|
||||
else
|
||||
throw new TerminologyServiceException("unable to find code system " + inc.getSystem().toString());
|
||||
}
|
||||
if (cs.getContent() != CodeSystemContentMode.COMPLETE)
|
||||
throw new TerminologyServiceException("Code system " + inc.getSystem().toString() + " is incomplete");
|
||||
if (cs.hasVersion())
|
||||
if (!existsInParams(params, "version", new UriType(cs.getUrl() + "|" + cs.getVersion())))
|
||||
params.add(new ValueSetExpansionParameterComponent().setName("version").setValue(new UriType(cs.getUrl() + "|" + cs.getVersion())));
|
||||
|
||||
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,
|
||||
CodeSystemUtilities.isInactive(cs, c.getCode()), imports);
|
||||
}
|
||||
}
|
||||
if (inc.getFilter().size() > 1) {
|
||||
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) {
|
||||
ConceptSetFilterComponent fc = inc.getFilter().get(0);
|
||||
if ("concept".equals(fc.getProperty()) && fc.getOp() == FilterOperator.ISA) {
|
||||
// special: all codes in the target code system under the value
|
||||
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue());
|
||||
if (def == null)
|
||||
throw new TerminologyServiceException("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
|
||||
addCodeAndDescendents(cs, inc.getSystem(), def, null, profile, imports);
|
||||
} else if ("concept".equals(fc.getProperty()) && fc.getOp() == FilterOperator.DESCENDENTOF) {
|
||||
// special: all codes in the target code system under the value
|
||||
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue());
|
||||
if (def == null)
|
||||
throw new TerminologyServiceException("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
|
||||
for (ConceptDefinitionComponent c : def.getConcept())
|
||||
addCodeAndDescendents(cs, inc.getSystem(), c, null, profile, imports);
|
||||
} else if ("display".equals(fc.getProperty()) && fc.getOp() == FilterOperator.EQUAL) {
|
||||
// gg; note: wtf is this: if the filter is display=v, look up the code 'v', and see if it's diplsay is 'v'?
|
||||
canBeHeirarchy = false;
|
||||
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue());
|
||||
if (def != null) {
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<ConceptDefinitionDesignationComponent> convertDesignations(List<ConceptReferenceDesignationComponent> list) {
|
||||
List<ConceptDefinitionDesignationComponent> res = new ArrayList<CodeSystem.ConceptDefinitionDesignationComponent>();
|
||||
for (ConceptReferenceDesignationComponent t : list) {
|
||||
ConceptDefinitionDesignationComponent c = new ConceptDefinitionDesignationComponent();
|
||||
c.setLanguage(t.getLanguage());
|
||||
c.setUse(t.getUse());
|
||||
c.setValue(t.getValue());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private String key(String uri, String code) {
|
||||
return "{" + uri + "}" + code;
|
||||
}
|
||||
|
||||
private String key(ValueSetExpansionContainsComponent c) {
|
||||
return key(c.getSystem(), c.getCode());
|
||||
}
|
||||
|
||||
}
|
||||
package org.hl7.fhir.dstu3.terminologies;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
||||
/*
|
||||
* 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.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
import org.hl7.fhir.dstu3.context.IWorkerContext;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionDesignationComponent;
|
||||
import org.hl7.fhir.dstu3.model.DateTimeType;
|
||||
import org.hl7.fhir.dstu3.model.ExpansionProfile;
|
||||
import org.hl7.fhir.dstu3.model.Factory;
|
||||
import org.hl7.fhir.dstu3.model.PrimitiveType;
|
||||
import org.hl7.fhir.dstu3.model.Type;
|
||||
import org.hl7.fhir.dstu3.model.UriType;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptReferenceComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptReferenceDesignationComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetFilterComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.FilterOperator;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetComposeComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionParameterComponent;
|
||||
import org.hl7.fhir.dstu3.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.exceptions.NoTerminologyServiceException;
|
||||
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
||||
public class ValueSetExpanderSimple implements ValueSetExpander {
|
||||
|
||||
private List<ValueSetExpansionContainsComponent> codes = new ArrayList<ValueSet.ValueSetExpansionContainsComponent>();
|
||||
private List<ValueSetExpansionContainsComponent> roots = new ArrayList<ValueSet.ValueSetExpansionContainsComponent>();
|
||||
private Map<String, ValueSetExpansionContainsComponent> map = new HashMap<String, ValueSet.ValueSetExpansionContainsComponent>();
|
||||
private IWorkerContext context;
|
||||
private boolean canBeHeirarchy = true;
|
||||
private Set<String> excludeKeys = new HashSet<String>();
|
||||
private Set<String> excludeSystems = new HashSet<String>();
|
||||
private ValueSetExpanderFactory factory;
|
||||
private ValueSet focus;
|
||||
private int maxExpansionSize = 500;
|
||||
|
||||
private int total;
|
||||
|
||||
public ValueSetExpanderSimple(IWorkerContext context, ValueSetExpanderFactory factory) {
|
||||
super();
|
||||
this.context = context;
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
public void setMaxExpansionSize(int theMaxExpansionSize) {
|
||||
maxExpansionSize = theMaxExpansionSize;
|
||||
}
|
||||
|
||||
private ValueSetExpansionContainsComponent addCode(String system, String code, String display, ValueSetExpansionContainsComponent parent, List<ConceptDefinitionDesignationComponent> designations,
|
||||
ExpansionProfile profile, boolean isAbstract, boolean inactive, List<ValueSet> filters) {
|
||||
if (filters != null && !filters.isEmpty() && !filterContainsCode(filters, system, code))
|
||||
return null;
|
||||
ValueSetExpansionContainsComponent n = new ValueSet.ValueSetExpansionContainsComponent();
|
||||
n.setSystem(system);
|
||||
n.setCode(code);
|
||||
if (isAbstract)
|
||||
n.setAbstract(true);
|
||||
if (inactive)
|
||||
n.setInactive(true);
|
||||
|
||||
if (profile.getIncludeDesignations() && designations != null) {
|
||||
for (ConceptDefinitionDesignationComponent t : designations) {
|
||||
ToolingExtensions.addLanguageTranslation(n, t.getLanguage(), t.getValue());
|
||||
}
|
||||
}
|
||||
ConceptDefinitionDesignationComponent t = profile.hasLanguage() ? getMatchingLang(designations, profile.getLanguage()) : null;
|
||||
if (t == null)
|
||||
n.setDisplay(display);
|
||||
else
|
||||
n.setDisplay(t.getValue());
|
||||
|
||||
String s = key(n);
|
||||
if (map.containsKey(s) || excludeKeys.contains(s)) {
|
||||
canBeHeirarchy = false;
|
||||
} else {
|
||||
codes.add(n);
|
||||
map.put(s, n);
|
||||
total++;
|
||||
}
|
||||
if (canBeHeirarchy && parent != null) {
|
||||
parent.getContains().add(n);
|
||||
} else {
|
||||
roots.add(n);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
private boolean filterContainsCode(List<ValueSet> filters, String system, String code) {
|
||||
for (ValueSet vse : filters)
|
||||
if (expansionContainsCode(vse.getExpansion().getContains(), system, code))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean expansionContainsCode(List<ValueSetExpansionContainsComponent> contains, String system, String code) {
|
||||
for (ValueSetExpansionContainsComponent cc : contains) {
|
||||
if (system.equals(cc.getSystem()) && code.equals(cc.getCode()))
|
||||
return true;
|
||||
if (expansionContainsCode(cc.getContains(), system, code))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private ConceptDefinitionDesignationComponent getMatchingLang(List<ConceptDefinitionDesignationComponent> list, String lang) {
|
||||
for (ConceptDefinitionDesignationComponent t : list)
|
||||
if (t.getLanguage().equals(lang))
|
||||
return t;
|
||||
for (ConceptDefinitionDesignationComponent t : list)
|
||||
if (t.getLanguage().startsWith(lang))
|
||||
return t;
|
||||
return null;
|
||||
}
|
||||
|
||||
private void addCodeAndDescendents(CodeSystem cs, String system, ConceptDefinitionComponent def, ValueSetExpansionContainsComponent parent, ExpansionProfile profile, List<ValueSet> filters)
|
||||
throws FHIRException {
|
||||
if (!CodeSystemUtilities.isDeprecated(cs, def)) {
|
||||
ValueSetExpansionContainsComponent np = null;
|
||||
boolean abs = CodeSystemUtilities.isNotSelectable(cs, def);
|
||||
boolean inc = CodeSystemUtilities.isInactive(cs, def);
|
||||
if (canBeHeirarchy || !abs)
|
||||
np = addCode(system, def.getCode(), def.getDisplay(), parent, def.getDesignation(), profile, abs, inc, filters);
|
||||
for (ConceptDefinitionComponent c : def.getConcept())
|
||||
addCodeAndDescendents(cs, system, c, np, profile, filters);
|
||||
} else
|
||||
for (ConceptDefinitionComponent c : def.getConcept())
|
||||
addCodeAndDescendents(cs, system, c, null, profile, filters);
|
||||
|
||||
}
|
||||
|
||||
private void addCodes(ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile, List<ValueSet> filters) throws ETooCostly {
|
||||
if (expand.getContains().size() > maxExpansionSize)
|
||||
throw new ETooCostly("Too many codes to display (>" + Integer.toString(expand.getContains().size()) + ")");
|
||||
for (ValueSetExpansionParameterComponent p : expand.getParameter()) {
|
||||
if (!existsInParams(params, p.getName(), p.getValue()))
|
||||
params.add(p);
|
||||
}
|
||||
|
||||
copyImportContains(expand.getContains(), null, profile, filters);
|
||||
}
|
||||
|
||||
private void excludeCode(String theSystem, String theCode) {
|
||||
ValueSetExpansionContainsComponent n = new ValueSet.ValueSetExpansionContainsComponent();
|
||||
n.setSystem(theSystem);
|
||||
n.setCode(theCode);
|
||||
String s = key(n);
|
||||
excludeKeys.add(s);
|
||||
}
|
||||
|
||||
private void excludeCodes(ConceptSetComponent exc, List<ValueSetExpansionParameterComponent> params) throws TerminologyServiceException {
|
||||
if (exc.hasSystem() && exc.getConcept().size() == 0 && exc.getFilter().size() == 0) {
|
||||
excludeSystems.add(exc.getSystem());
|
||||
}
|
||||
|
||||
if (exc.hasValueSet())
|
||||
throw new Error("Processing Value set references in exclude is not yet done");
|
||||
// importValueSet(imp.getValue(), params, profile);
|
||||
|
||||
CodeSystem cs = context.fetchCodeSystem(exc.getSystem());
|
||||
if ((cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) && context.supportsSystem(exc.getSystem())) {
|
||||
excludeCodes(context.expandVS(exc, false), params);
|
||||
return;
|
||||
}
|
||||
|
||||
for (ConceptReferenceComponent c : exc.getConcept()) {
|
||||
excludeCode(exc.getSystem(), c.getCode());
|
||||
}
|
||||
|
||||
if (exc.getFilter().size() > 0)
|
||||
throw new NotImplementedException("not done yet");
|
||||
}
|
||||
|
||||
private void excludeCodes(ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params) {
|
||||
for (ValueSetExpansionContainsComponent c : expand.getContains()) {
|
||||
excludeCode(c.getSystem(), c.getCode());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean existsInParams(List<ValueSetExpansionParameterComponent> params, String name, Type value) {
|
||||
for (ValueSetExpansionParameterComponent p : params) {
|
||||
if (p.getName().equals(name) && PrimitiveType.compareDeep(p.getValue(), value, false))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSetExpansionOutcome expand(ValueSet source, ExpansionProfile profile) {
|
||||
|
||||
if (profile == null)
|
||||
profile = makeDefaultExpansion();
|
||||
try {
|
||||
focus = source.copy();
|
||||
focus.setExpansion(new ValueSet.ValueSetExpansionComponent());
|
||||
focus.getExpansion().setTimestampElement(DateTimeType.now());
|
||||
focus.getExpansion().setIdentifier(Factory.createUUID());
|
||||
if (!profile.getUrl().startsWith("urn:uuid:"))
|
||||
focus.getExpansion().addParameter().setName("profile").setValue(new UriType(profile.getUrl()));
|
||||
|
||||
if (source.hasCompose())
|
||||
handleCompose(source.getCompose(), focus.getExpansion().getParameter(), profile);
|
||||
|
||||
if (canBeHeirarchy) {
|
||||
for (ValueSetExpansionContainsComponent c : roots) {
|
||||
focus.getExpansion().getContains().add(c);
|
||||
}
|
||||
} else {
|
||||
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
|
||||
focus.getExpansion().getContains().add(c);
|
||||
c.getContains().clear(); // make sure any heirarchy is wiped
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (total > 0) {
|
||||
focus.getExpansion().setTotal(total);
|
||||
}
|
||||
|
||||
return new ValueSetExpansionOutcome(focus);
|
||||
} catch (RuntimeException e) {
|
||||
// TODO: we should put something more specific instead of just Exception below, since
|
||||
// it swallows bugs.. what would be expected to be caught there?
|
||||
throw 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
|
||||
// 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);
|
||||
res.setIncludeDesignations(false);
|
||||
return res;
|
||||
}
|
||||
|
||||
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());
|
||||
return def.getDisplay();
|
||||
}
|
||||
|
||||
private ConceptDefinitionComponent getConceptForCode(List<ConceptDefinitionComponent> clist, String code) {
|
||||
for (ConceptDefinitionComponent c : clist) {
|
||||
if (code.equals(c.getCode()))
|
||||
return c;
|
||||
ConceptDefinitionComponent v = getConceptForCode(c.getConcept(), code);
|
||||
if (v != null)
|
||||
return v;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void handleCompose(ValueSetComposeComponent compose, List<ValueSetExpansionParameterComponent> params, ExpansionProfile profile)
|
||||
throws ETooCostly, FileNotFoundException, IOException, FHIRException {
|
||||
// Exclude comes first because we build up a map of things to exclude
|
||||
for (ConceptSetComponent inc : compose.getExclude())
|
||||
excludeCodes(inc, params);
|
||||
canBeHeirarchy = !profile.getExcludeNested() && excludeKeys.isEmpty() && excludeSystems.isEmpty();
|
||||
boolean first = true;
|
||||
for (ConceptSetComponent inc : compose.getInclude()) {
|
||||
if (first == true)
|
||||
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");
|
||||
ValueSet vs = context.fetchResource(ValueSet.class, value);
|
||||
if (vs == null)
|
||||
throw new TerminologyServiceException("Unable to find imported value set " + value);
|
||||
ValueSetExpansionOutcome vso = factory.getExpander().expand(vs, profile);
|
||||
if (vso.getError() != null)
|
||||
throw new TerminologyServiceException("Unable to expand imported value set: " + vso.getError());
|
||||
if (vso.getService() != null)
|
||||
throw new TerminologyServiceException("Unable to expand imported value set " + value);
|
||||
if (vs.hasVersion())
|
||||
if (!existsInParams(params, "version", new UriType(vs.getUrl() + "|" + vs.getVersion())))
|
||||
params.add(new ValueSetExpansionParameterComponent().setName("version").setValue(new UriType(vs.getUrl() + "|" + vs.getVersion())));
|
||||
for (ValueSetExpansionParameterComponent p : vso.getValueset().getExpansion().getParameter()) {
|
||||
if (!existsInParams(params, p.getName(), p.getValue()))
|
||||
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
|
||||
return vso.getValueset();
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
if (!inc.hasSystem()) {
|
||||
if (imports.isEmpty()) // though this is not supposed to be the case
|
||||
return;
|
||||
ValueSet base = imports.get(0);
|
||||
imports.remove(0);
|
||||
copyImportContains(base.getExpansion().getContains(), null, profile, imports);
|
||||
} else {
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cs == null) {
|
||||
if (context.isNoTerminologyServer())
|
||||
throw new NoTerminologyServiceException("unable to find code system " + inc.getSystem().toString());
|
||||
else
|
||||
throw new TerminologyServiceException("unable to find code system " + inc.getSystem().toString());
|
||||
}
|
||||
if (cs.getContent() != CodeSystemContentMode.COMPLETE)
|
||||
throw new TerminologyServiceException("Code system " + inc.getSystem().toString() + " is incomplete");
|
||||
if (cs.hasVersion())
|
||||
if (!existsInParams(params, "version", new UriType(cs.getUrl() + "|" + cs.getVersion())))
|
||||
params.add(new ValueSetExpansionParameterComponent().setName("version").setValue(new UriType(cs.getUrl() + "|" + cs.getVersion())));
|
||||
|
||||
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,
|
||||
CodeSystemUtilities.isInactive(cs, c.getCode()), imports);
|
||||
}
|
||||
}
|
||||
if (inc.getFilter().size() > 1) {
|
||||
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) {
|
||||
ConceptSetFilterComponent fc = inc.getFilter().get(0);
|
||||
if ("concept".equals(fc.getProperty()) && fc.getOp() == FilterOperator.ISA) {
|
||||
// special: all codes in the target code system under the value
|
||||
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue());
|
||||
if (def == null)
|
||||
throw new TerminologyServiceException("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
|
||||
addCodeAndDescendents(cs, inc.getSystem(), def, null, profile, imports);
|
||||
} else if ("concept".equals(fc.getProperty()) && fc.getOp() == FilterOperator.DESCENDENTOF) {
|
||||
// special: all codes in the target code system under the value
|
||||
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue());
|
||||
if (def == null)
|
||||
throw new TerminologyServiceException("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
|
||||
for (ConceptDefinitionComponent c : def.getConcept())
|
||||
addCodeAndDescendents(cs, inc.getSystem(), c, null, profile, imports);
|
||||
} else if ("display".equals(fc.getProperty()) && fc.getOp() == FilterOperator.EQUAL) {
|
||||
// gg; note: wtf is this: if the filter is display=v, look up the code 'v', and see if it's diplsay is 'v'?
|
||||
canBeHeirarchy = false;
|
||||
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue());
|
||||
if (def != null) {
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<ConceptDefinitionDesignationComponent> convertDesignations(List<ConceptReferenceDesignationComponent> list) {
|
||||
List<ConceptDefinitionDesignationComponent> res = new ArrayList<CodeSystem.ConceptDefinitionDesignationComponent>();
|
||||
for (ConceptReferenceDesignationComponent t : list) {
|
||||
ConceptDefinitionDesignationComponent c = new ConceptDefinitionDesignationComponent();
|
||||
c.setLanguage(t.getLanguage());
|
||||
c.setUse(t.getUse());
|
||||
c.setValue(t.getValue());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private String key(String uri, String code) {
|
||||
return "{" + uri + "}" + code;
|
||||
}
|
||||
|
||||
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.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.junit.*;
|
||||
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
|
@ -177,7 +178,7 @@ public class ContextScanningDstu3Test {
|
|||
}
|
||||
|
||||
@Read
|
||||
public Observation read(@IdParam IdType theId) {
|
||||
public Observation read(@IdParam IdType theId) throws FHIRFormatError {
|
||||
Observation retVal = new Observation();
|
||||
retVal.setId(theId);
|
||||
retVal.addIdentifier().setSystem("ISYS").setValue("IVAL");
|
||||
|
|
|
@ -1023,7 +1023,7 @@ public class JsonParserDstu3Test {
|
|||
ourLog.info(encoded);
|
||||
|
||||
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("THE DIV")));
|
||||
assertThat(encoded, containsString("family"));
|
||||
|
@ -1057,7 +1057,7 @@ public class JsonParserDstu3Test {
|
|||
ourLog.info(encoded);
|
||||
|
||||
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, containsString("family"));
|
||||
assertThat(encoded, not(containsString("maritalStatus")));
|
||||
|
@ -1077,7 +1077,7 @@ public class JsonParserDstu3Test {
|
|||
ourLog.info(encoded);
|
||||
|
||||
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 + "\""));
|
||||
assertThat(encoded, not(containsString("THE DIV")));
|
||||
assertThat(encoded, containsString("family"));
|
||||
|
|
|
@ -1519,7 +1519,7 @@ public class XmlParserDstu3Test {
|
|||
ourLog.info(encoded);
|
||||
|
||||
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>"));
|
||||
assertThat(encoded, not(containsString("text")));
|
||||
assertThat(encoded, not(containsString("THE DIV")));
|
||||
|
@ -1666,7 +1666,7 @@ public class XmlParserDstu3Test {
|
|||
ourLog.info(encoded);
|
||||
|
||||
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>"));
|
||||
assertThat(encoded, not(containsString("THE DIV")));
|
||||
assertThat(encoded, containsString("family"));
|
||||
|
@ -1688,7 +1688,7 @@ public class XmlParserDstu3Test {
|
|||
|
||||
assertThat(encoded, containsString("<Patient"));
|
||||
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>"));
|
||||
assertThat(encoded, not(containsString("THE DIV")));
|
||||
assertThat(encoded, containsString("family"));
|
||||
|
|
|
@ -504,7 +504,7 @@ public class GenericClientDstu3Test {
|
|||
client.read().resource(Patient.class).withId("1").execute();
|
||||
fail();
|
||||
} catch (FhirClientConnectionException e) {
|
||||
assertEquals("java.lang.IllegalStateException", e.getMessage());
|
||||
assertEquals(null, e.getMessage());
|
||||
}
|
||||
|
||||
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.model.api.annotation.Child;
|
||||
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.util.TestUtil;
|
||||
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.ValueSet.ConceptDefinitionComponent;
|
||||
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.INarrative;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||
import org.junit.*;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
|
@ -148,7 +144,7 @@ public class JsonParserHl7OrgDstu2Test {
|
|||
ourLog.info(encoded);
|
||||
|
||||
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("THE DIV")));
|
||||
assertThat(encoded, containsString("family"));
|
||||
|
@ -780,7 +776,7 @@ public class JsonParserHl7OrgDstu2Test {
|
|||
|
||||
assertThat(encoded, containsString("Patient"));
|
||||
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, containsString("family"));
|
||||
assertThat(encoded, not(containsString("maritalStatus")));
|
||||
|
@ -802,7 +798,7 @@ public class JsonParserHl7OrgDstu2Test {
|
|||
assertThat(encoded, containsString("Patient"));
|
||||
assertThat(encoded, stringContainsInOrder("\"tag\"",
|
||||
"\"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, containsString("family"));
|
||||
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.Identifier.IdentifierUse;
|
||||
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.Organization;
|
||||
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.api.IBaseResource;
|
||||
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.junit.After;
|
||||
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.model.api.annotation.Child;
|
||||
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.MyPatientWithOneDeclaredExtension;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
|
@ -1050,7 +1046,7 @@ public class XmlParserHl7OrgDstu2Test {
|
|||
ourLog.info(encoded);
|
||||
|
||||
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>"));
|
||||
assertThat(encoded, not(containsString("text")));
|
||||
assertThat(encoded, not(containsString("THE DIV")));
|
||||
|
@ -1169,7 +1165,7 @@ public class XmlParserHl7OrgDstu2Test {
|
|||
ourLog.info(encoded);
|
||||
|
||||
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>"));
|
||||
assertThat(encoded, not(containsString("THE DIV")));
|
||||
assertThat(encoded, containsString("family"));
|
||||
|
@ -1191,7 +1187,7 @@ public class XmlParserHl7OrgDstu2Test {
|
|||
|
||||
assertThat(encoded, containsString("<Patient"));
|
||||
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>"));
|
||||
assertThat(encoded, not(containsString("THE DIV")));
|
||||
assertThat(encoded, containsString("family"));
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
package org.hl7.fhir.r4.conformance;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r4.context.IWorkerContext;
|
||||
|
@ -29,7 +26,7 @@ public class ConstraintJavaGenerator {
|
|||
}
|
||||
|
||||
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)) {
|
||||
System.out.println("Cannot generate Java code for profile "+sd.getUrl()+" because the name \""+name+"\" is not a valid Java class name");
|
||||
return null;
|
||||
|
@ -46,6 +43,7 @@ public class ConstraintJavaGenerator {
|
|||
|
||||
dest.write("}\r\n");
|
||||
dest.flush();
|
||||
dest.close();
|
||||
return destFile.getAbsolutePath();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package org.hl7.fhir.r4.conformance;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
@ -8,6 +11,9 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
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.formats.IParser;
|
||||
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.ElementDefinitionConstraintComponent;
|
||||
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.Enumerations.BindingStrength;
|
||||
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.utils.DefinitionNavigator;
|
||||
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.TextFile;
|
||||
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.Source;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* A engine that generates difference analysis between two sets of structure
|
||||
* definitions, typically from 2 different implementation guides.
|
||||
|
@ -398,8 +407,11 @@ public class ProfileComparer {
|
|||
if (isExtension(left.path()))
|
||||
return compareExtensions(outcome, path, superset, subset, left, right);
|
||||
// return true;
|
||||
else
|
||||
else {
|
||||
ElementDefinitionSlicingComponent slicingL = left.current().getSlicing();
|
||||
ElementDefinitionSlicingComponent slicingR = right.current().getSlicing();
|
||||
throw new DefinitionException("Slicing is not handled yet");
|
||||
}
|
||||
// todo: name
|
||||
}
|
||||
|
||||
|
@ -629,8 +641,8 @@ public class ProfileComparer {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
subBinding.setValueSet(new Reference().setReference("#"+addValueSet(cvs)));
|
||||
superBinding.setValueSet(new Reference().setReference("#"+addValueSet(unite(superset, outcome, path, lvs, rvs))));
|
||||
subBinding.setValueSet("#"+addValueSet(cvs));
|
||||
superBinding.setValueSet("#"+addValueSet(unite(superset, outcome, path, lvs, rvs)));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -649,11 +661,11 @@ public class ProfileComparer {
|
|||
ValueSet lvs = resolveVS(outcome.left, left.getValueSet());
|
||||
ValueSet rvs = resolveVS(outcome.left, right.getValueSet());
|
||||
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)
|
||||
union.setValueSet(new Reference().setReference("#"+addValueSet(lvs)));
|
||||
union.setValueSet("#"+addValueSet(lvs));
|
||||
else if (rvs != null)
|
||||
union.setValueSet(new Reference().setReference("#"+addValueSet(rvs)));
|
||||
union.setValueSet("#"+addValueSet(rvs));
|
||||
}
|
||||
return union;
|
||||
}
|
||||
|
@ -710,17 +722,10 @@ public class ProfileComparer {
|
|||
return false;
|
||||
}
|
||||
|
||||
private ValueSet resolveVS(StructureDefinition ctxtLeft, Type vsRef) {
|
||||
private ValueSet resolveVS(StructureDefinition ctxtLeft, String vsRef) {
|
||||
if (vsRef == null)
|
||||
return null;
|
||||
if (vsRef instanceof UriType)
|
||||
return null;
|
||||
else {
|
||||
Reference ref = (Reference) vsRef;
|
||||
if (!ref.hasReference())
|
||||
return null;
|
||||
return context.fetchResource(ValueSet.class, ref.getReference());
|
||||
}
|
||||
return context.fetchResource(ValueSet.class, vsRef);
|
||||
}
|
||||
|
||||
private ValueSet intersectByDefinition(ValueSet lvs, ValueSet rvs) {
|
||||
|
@ -1166,6 +1171,100 @@ public class ProfileComparer {
|
|||
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.tuple.ImmutablePair;
|
||||
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.elementmodel.TurtleParser;
|
||||
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.terminologies.ValueSetExpander;
|
||||
import org.hl7.fhir.r4.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.stringtemplate.v4.ST;
|
||||
|
||||
public class ShExGenerator {
|
||||
|
@ -388,7 +388,7 @@ public class ShExGenerator {
|
|||
for (String dt : new HashSet<String>(datatypes)) {
|
||||
if (!emittedDatatypes.contains(dt)) {
|
||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class,
|
||||
ProfileUtilities.sdNs(dt));
|
||||
ProfileUtilities.sdNs(dt, null));
|
||||
// TODO: Figure out why the line below doesn't work
|
||||
// if (sd != null && !uniq_structures.contains(sd))
|
||||
if(sd != null && !uniq_structure_urls.contains(sd.getUrl()))
|
||||
|
@ -748,23 +748,11 @@ public class ShExGenerator {
|
|||
|
||||
|
||||
// TODO: find a utility that implements this
|
||||
private ValueSet resolveBindingReference(DomainResource ctxt, Type reference) {
|
||||
if (reference instanceof UriType) {
|
||||
return context.fetchResource(ValueSet.class, ((UriType) reference).getValue().toString());
|
||||
}
|
||||
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
|
||||
private ValueSet resolveBindingReference(DomainResource ctxt, String reference) {
|
||||
try {
|
||||
return context.fetchResource(ValueSet.class, reference);
|
||||
} catch (Throwable e) {
|
||||
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.ConceptMap;
|
||||
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.Parameters;
|
||||
import org.hl7.fhir.r4.model.Resource;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||
import org.hl7.fhir.r4.model.StructureMap;
|
||||
|
@ -194,8 +194,8 @@ public interface IWorkerContext {
|
|||
|
||||
// -- Terminology services ------------------------------------------------------
|
||||
|
||||
public ExpansionProfile getExpansionProfile();
|
||||
public void setExpansionProfile(ExpansionProfile expProfile);
|
||||
public Parameters getExpansionParameters();
|
||||
public void setExpansionProfile(Parameters expParameters);
|
||||
|
||||
// these are the terminology services used internally by the tools
|
||||
/**
|
||||
|
@ -256,7 +256,7 @@ public interface IWorkerContext {
|
|||
* @return
|
||||
* @throws FHIRException
|
||||
*/
|
||||
public ValueSetExpansionComponent expandVS(ConceptSetComponent inc, boolean heirarchical) throws TerminologyServiceException;
|
||||
public ValueSetExpansionOutcome expandVS(ConceptSetComponent inc, boolean heirarchical) throws TerminologyServiceException;
|
||||
|
||||
public class ValidationResult {
|
||||
private ConceptDefinitionComponent definition;
|
||||
|
@ -286,7 +286,7 @@ public interface IWorkerContext {
|
|||
}
|
||||
|
||||
public boolean isOk() {
|
||||
return definition != null;
|
||||
return severity == null || severity == IssueSeverity.INFORMATION || severity == IssueSeverity.WARNING;
|
||||
}
|
||||
|
||||
public String getDisplay() {
|
||||
|
@ -314,6 +314,16 @@ public interface IWorkerContext {
|
|||
public TerminologyServiceErrorClass getErrorClass() {
|
||||
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
|
||||
*/
|
||||
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(CodeableConcept code, ValueSet vs);
|
||||
|
||||
|
@ -391,10 +402,16 @@ public interface IWorkerContext {
|
|||
}
|
||||
|
||||
public void setLogger(ILoggingService logger);
|
||||
public ILoggingService getLogger();
|
||||
|
||||
public boolean isNoTerminologyServer();
|
||||
|
||||
public TranslationServices translator();
|
||||
public List<StructureMap> listTransforms();
|
||||
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.OIDUtils;
|
||||
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.IssueType;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
|
||||
|
@ -92,12 +93,13 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
|
|||
private String date;
|
||||
private IValidatorFactory validatorFactory;
|
||||
private UcumService ucumService;
|
||||
private boolean ignoreProfileErrors;
|
||||
|
||||
public SimpleWorkerContext() {
|
||||
public SimpleWorkerContext() throws FileNotFoundException, IOException, FHIRException {
|
||||
super();
|
||||
}
|
||||
|
||||
public SimpleWorkerContext(SimpleWorkerContext other) {
|
||||
public SimpleWorkerContext(SimpleWorkerContext other) throws FileNotFoundException, IOException, FHIRException {
|
||||
super();
|
||||
copy(other);
|
||||
}
|
||||
|
@ -130,6 +132,26 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
|
|||
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 {
|
||||
SimpleWorkerContext res = new SimpleWorkerContext();
|
||||
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 {
|
||||
Bundle f;
|
||||
Bundle f = null;
|
||||
try {
|
||||
if (loader != null)
|
||||
f = loader.loadBundle(stream, true);
|
||||
else {
|
||||
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) {
|
||||
throw new org.hl7.fhir.exceptions.FHIRFormatError(e1.getMessage(), e1);
|
||||
}
|
||||
for (BundleEntryComponent e : f.getEntry()) {
|
||||
|
||||
if (e.getFullUrl() == null) {
|
||||
logger.logDebugMessage(LogCategory.CONTEXT, "unidentified resource in " + name+" (no fullUrl)");
|
||||
}
|
||||
cacheResource(e.getResource());
|
||||
if (f != null)
|
||||
for (BundleEntryComponent e : f.getEntry()) {
|
||||
cacheResource(e.getResource());
|
||||
}
|
||||
}
|
||||
|
||||
private void loadFromPack(String path, IContextResourceLoader loader) throws FileNotFoundException, IOException, FHIRException {
|
||||
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 {
|
||||
loadDefinitionItem(file, new CSFileInputStream(file), loader);
|
||||
|
@ -423,6 +459,18 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
|
|||
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 {
|
||||
for (String n : new File(folder).list()) {
|
||||
if (n.endsWith(".json"))
|
||||
|
@ -507,12 +555,13 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
|
|||
List<ValidationMessage> msgs = new ArrayList<ValidationMessage>();
|
||||
List<String> errors = new ArrayList<String>();
|
||||
ProfileUtilities pu = new ProfileUtilities(this, msgs, this);
|
||||
pu.setThrowException(false);
|
||||
pu.sortDifferential(sd, p, p.getUrl(), errors);
|
||||
for (String err : errors)
|
||||
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());
|
||||
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());
|
||||
}
|
||||
if (!p.hasSnapshot())
|
||||
|
@ -531,6 +580,14 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
|
|||
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.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
||||
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.xhtml.XhtmlComposer;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||
|
@ -470,9 +472,30 @@ public class Element extends Base {
|
|||
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) {
|
||||
if (children == null)
|
||||
return null;
|
||||
|
@ -660,7 +683,7 @@ public class Element extends Base {
|
|||
private List<ElementDefinition> children;
|
||||
public ElementSortComparator(Element e, Property property) {
|
||||
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())
|
||||
children = sd.getSnapshot().getElement();
|
||||
else
|
||||
|
|
|
@ -80,7 +80,7 @@ public class JsonParser extends ParserBase {
|
|||
assert (map.containsKey(obj));
|
||||
return parse(obj);
|
||||
} 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));
|
||||
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);
|
||||
} else {
|
||||
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)
|
||||
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);
|
||||
|
@ -447,7 +447,11 @@ public class JsonParser extends ParserBase {
|
|||
else if (Utilities.existsInList(type, "integer", "unsignedInt", "positiveInt"))
|
||||
json.value(new Integer(item.getValue()));
|
||||
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
|
||||
json.value(item.getValue());
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ public class ObjectConverter {
|
|||
if (base == null)
|
||||
return null;
|
||||
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)
|
||||
throw new FHIRException("Unable to find definition for type "+tn);
|
||||
Element res = new Element(property.getName(), property);
|
||||
|
@ -86,7 +86,7 @@ public class ObjectConverter {
|
|||
ByteArrayOutputStream bo = new ByteArrayOutputStream();
|
||||
try {
|
||||
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());
|
||||
} catch (IOException e) {
|
||||
// won't happen
|
||||
|
|
|
@ -3,13 +3,16 @@ package org.hl7.fhir.r4.elementmodel;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hl7.fhir.r4.context.IWorkerContext;
|
||||
import org.hl7.fhir.r4.formats.FormatUtilities;
|
||||
import org.hl7.fhir.r4.formats.IParser.OutputStyle;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||
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.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
|
@ -33,7 +36,7 @@ public abstract class ParserBase {
|
|||
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");
|
||||
|
||||
// StructureDefinition sd = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/"+code);
|
||||
// StructureDefinition sd = context.fetchTypeDefinition(code);
|
||||
// return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
|
||||
}
|
||||
|
||||
|
@ -41,7 +44,8 @@ public abstract class ParserBase {
|
|||
protected ValidationPolicy policy;
|
||||
protected List<ValidationMessage> errors;
|
||||
protected ILinkResolver linkResolver;
|
||||
|
||||
protected boolean showDecorations;
|
||||
|
||||
public ParserBase(IWorkerContext context) {
|
||||
super();
|
||||
this.context = context;
|
||||
|
@ -77,7 +81,7 @@ public abstract class ParserBase {
|
|||
return null;
|
||||
}
|
||||
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"))
|
||||
return sd;
|
||||
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()) {
|
||||
if (name.equals(sd.getIdElement().getIdPart())) {
|
||||
if (name.equals(sd.getType()) && sd.getDerivation() == TypeDerivationRule.SPECIALIZATION) {
|
||||
return sd;
|
||||
}
|
||||
}
|
||||
|
@ -118,7 +122,13 @@ public abstract class ParserBase {
|
|||
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.TypeDetails;
|
||||
import org.hl7.fhir.r4.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.r4.utils.TypesUtilities;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
|
@ -88,7 +89,10 @@ public class Property {
|
|||
} else
|
||||
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) {
|
||||
return structure.getId();
|
||||
if (Utilities.existsInList(ed.getId(), "Element.id", "Extension.url"))
|
||||
return "string";
|
||||
else
|
||||
return structure.getId();
|
||||
} else
|
||||
return ed.getType().get(0).getCode();
|
||||
}
|
||||
|
@ -135,8 +139,10 @@ public class Property {
|
|||
* @param E.g. "integer"
|
||||
*/
|
||||
public boolean isPrimitive(String code) {
|
||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/"+code);
|
||||
return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
|
||||
return TypesUtilities.isPrimitive(code);
|
||||
// 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) {
|
||||
|
@ -191,7 +197,7 @@ public class Property {
|
|||
return false;
|
||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, structure.getUrl().substring(0, structure.getUrl().lastIndexOf("/")+1)+getType(name));
|
||||
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)
|
||||
return true;
|
||||
if (sd == null || sd.getKind() != StructureDefinitionKind.LOGICAL)
|
||||
|
@ -274,7 +280,7 @@ public class Property {
|
|||
assert aType.getProfile().size() == 1;
|
||||
url = aType.getProfile().get(0).getValue();
|
||||
} else {
|
||||
url = ProfileUtilities.sdNs(t);
|
||||
url = ProfileUtilities.sdNs(t, context.getOverrideVersionNs());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.hl7.fhir.r4.elementmodel;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
@ -7,8 +8,10 @@ import java.io.UnsupportedEncodingException;
|
|||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.sql.rowset.spi.XmlWriter;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
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.FHIRException;
|
||||
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.validation.ValidationMessage.IssueSeverity;
|
||||
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.XhtmlNode;
|
||||
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.XMLReader;
|
||||
|
||||
import com.sun.webkit.ContextMenu.ShowContext;
|
||||
|
||||
public class XmlParser extends ParserBase {
|
||||
private boolean allowXsiLocation;
|
||||
|
||||
|
@ -63,7 +71,6 @@ public class XmlParser extends ParserBase {
|
|||
this.allowXsiLocation = allowXsiLocation;
|
||||
}
|
||||
|
||||
|
||||
public Element parse(InputStream stream) throws FHIRFormatError, DefinitionException, FHIRException, IOException {
|
||||
Document doc = null;
|
||||
try {
|
||||
|
@ -115,7 +122,7 @@ public class XmlParser extends ParserBase {
|
|||
}
|
||||
|
||||
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();
|
||||
while (node != null) {
|
||||
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 {
|
||||
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);
|
||||
String ns = FormatUtilities.FHIR_NS;
|
||||
if (ToolingExtensions.hasExtension(prop.getDefinition(), "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace"))
|
||||
|
@ -237,13 +244,22 @@ public class XmlParser extends ParserBase {
|
|||
if (property != null) {
|
||||
String av = attr.getNodeValue();
|
||||
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())
|
||||
context.setValue(av);
|
||||
else
|
||||
context.getChildren().add(new Element(property.getName(), property, property.getType(), av).markLocation(line(node), col(node)));
|
||||
} else if (!allowXsiLocation || !attr.getNodeName().endsWith(":schemaLocation") ) {
|
||||
logError(line(node), col(node), path, IssueType.STRUCTURE, "Undefined attribute '@"+attr.getNodeName()+"' on "+node.getNodeName()+" for type "+context.fhirType()+" (properties = "+properties+")", IssueSeverity.ERROR);
|
||||
} else {
|
||||
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());
|
||||
if (property != null) {
|
||||
if (!property.isChoice() && "xhtml".equals(property.getType())) {
|
||||
XhtmlNode xhtml = new XhtmlParser().setValidatorMode(true).parseHtmlNode((org.w3c.dom.Element) child);
|
||||
context.getChildren().add(new Element("div", property, "xhtml", new XhtmlComposer(XhtmlComposer.XML, false).compose(xhtml)).setXhtml(xhtml).markLocation(line(child), col(child)));
|
||||
XhtmlNode xhtml;
|
||||
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 {
|
||||
String npath = path+"/"+pathPrefix(child.getNamespaceURI())+child.getLocalName();
|
||||
Element n = new Element(child.getLocalName(), property).markLocation(line(child), col(child));
|
||||
|
@ -328,7 +348,7 @@ public class XmlParser extends ParserBase {
|
|||
return null;
|
||||
}
|
||||
|
||||
private String convertForDateFormat(String fmt, String av) throws FHIRException {
|
||||
private String convertForDateFormatFromExternal(String fmt, String av) throws FHIRException {
|
||||
if ("v3".equals(fmt)) {
|
||||
DateTimeType d = DateTimeType.parseV3(av);
|
||||
return d.asStringValue();
|
||||
|
@ -336,10 +356,18 @@ public class XmlParser extends ParserBase {
|
|||
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 {
|
||||
org.w3c.dom.Element res = XMLUtil.getFirstChild(container);
|
||||
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)
|
||||
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);
|
||||
|
@ -365,14 +393,32 @@ public class XmlParser extends ParserBase {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean isAttr(Property property) {
|
||||
for (Enumeration<PropertyRepresentation> r : property.getDefinition().getRepresentation()) {
|
||||
if (r.getValue() == PropertyRepresentation.XMLATTR) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private boolean isAttr(Property property) {
|
||||
for (Enumeration<PropertyRepresentation> r : property.getDefinition().getRepresentation()) {
|
||||
if (r.getValue() == PropertyRepresentation.XMLATTR) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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) {
|
||||
for (Enumeration<PropertyRepresentation> r : property.getDefinition().getRepresentation()) {
|
||||
|
@ -384,16 +430,30 @@ public class XmlParser extends ParserBase {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void compose(Element e, OutputStream stream, OutputStyle style, String base) throws IOException {
|
||||
XMLWriter xml = new XMLWriter(stream, "UTF-8");
|
||||
public void compose(Element e, OutputStream stream, OutputStyle style, String base) throws IOException, FHIRException {
|
||||
XMLWriter xml = new XMLWriter(stream, "UTF-8");
|
||||
xml.setSortAttributes(false);
|
||||
xml.setPretty(style == OutputStyle.PRETTY);
|
||||
xml.start();
|
||||
xml.setDefaultNamespace(e.getProperty().getNamespace());
|
||||
if (hasTypeAttr(e))
|
||||
xml.namespace("http://www.w3.org/2001/XMLSchema-instance", "xsi");
|
||||
composeElement(xml, e, e.getType(), true);
|
||||
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 {
|
||||
xml.start();
|
||||
xml.setDefaultNamespace(e.getProperty().getNamespace());
|
||||
|
@ -401,7 +461,14 @@ public class XmlParser extends ParserBase {
|
|||
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()) {
|
||||
xml.comment(s, true);
|
||||
}
|
||||
|
@ -413,12 +480,19 @@ public class XmlParser extends ParserBase {
|
|||
xml.exit(elementName);
|
||||
} else if (element.isPrimitive() || (element.hasType() && isPrimitive(element.getType()))) {
|
||||
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())) {
|
||||
if (linkResolver != null)
|
||||
xml.link(linkResolver.resolveProperty(element.getProperty()));
|
||||
xml.text(element.getValue());
|
||||
} else {
|
||||
if (isTypeAttr(element.getProperty()) && !Utilities.noString(element.getType())) {
|
||||
xml.attribute("xsi:type", element.getType());
|
||||
}
|
||||
if (element.hasValue()) {
|
||||
if (linkResolver != null)
|
||||
xml.link(linkResolver.resolveType(element.getType()));
|
||||
|
@ -432,14 +506,20 @@ public class XmlParser extends ParserBase {
|
|||
composeElement(xml, child, child.getName(), false);
|
||||
xml.exit(elementName);
|
||||
} else
|
||||
xml.element(elementName);
|
||||
xml.element(elementName);
|
||||
}
|
||||
} else {
|
||||
if (isTypeAttr(element.getProperty()) && !Utilities.noString(element.getType())) {
|
||||
xml.attribute("xsi:type", element.getType());
|
||||
}
|
||||
for (Element child : element.getChildren()) {
|
||||
if (isAttr(child.getProperty())) {
|
||||
if (linkResolver != null)
|
||||
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)
|
||||
|
|
|
@ -26,6 +26,7 @@ public interface JsonCreator {
|
|||
void value(Boolean 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;
|
||||
|
||||
|
|
|
@ -8,8 +8,6 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
public class JsonCreatorCanonical implements JsonCreator {
|
||||
|
||||
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 Integer value;
|
||||
private JsonCanIntegerValue(String name, Integer value) {
|
||||
|
@ -74,12 +80,12 @@ public class JsonCreatorCanonical implements JsonCreator {
|
|||
|
||||
Stack<JsonCanObject> stack;
|
||||
JsonCanObject root;
|
||||
JsonWriter gson;
|
||||
JsonCreatorDirect jj;
|
||||
String name;
|
||||
|
||||
public JsonCreatorCanonical(OutputStreamWriter osw) {
|
||||
stack = new Stack<JsonCreatorCanonical.JsonCanObject>();
|
||||
gson = new JsonWriter(osw);
|
||||
jj = new JsonCreatorDirect(osw);
|
||||
name = null;
|
||||
}
|
||||
|
||||
|
@ -93,7 +99,7 @@ public class JsonCreatorCanonical implements JsonCreator {
|
|||
public void setIndent(String indent) {
|
||||
if (!indent.equals(""))
|
||||
throw new Error("do not use pretty when canonical is set");
|
||||
gson.setIndent(indent);
|
||||
jj.setIndent(indent);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -135,6 +141,11 @@ public class JsonCreatorCanonical implements JsonCreator {
|
|||
public void value(BigDecimal value) throws IOException {
|
||||
stack.peek().addProp(new JsonCanNumberValue(takeName(), value));
|
||||
}
|
||||
@Override
|
||||
public void valueNum(String value) throws IOException {
|
||||
stack.peek().addProp(new JsonCanPresentedNumberValue(takeName(), value));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void value(Integer value) throws IOException {
|
||||
|
@ -161,24 +172,26 @@ public class JsonCreatorCanonical implements JsonCreator {
|
|||
}
|
||||
|
||||
private void writeObject(JsonCanObject obj) throws IOException {
|
||||
gson.beginObject();
|
||||
jj.beginObject();
|
||||
List<String> names = new ArrayList<String>();
|
||||
for (JsonCanValue v : obj.children)
|
||||
names.add(v.name);
|
||||
Collections.sort(names);
|
||||
for (String n : names) {
|
||||
gson.name(n);
|
||||
jj.name(n);
|
||||
JsonCanValue v = getPropForName(n, obj.children);
|
||||
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)
|
||||
gson.value(((JsonCanIntegerValue) v).value);
|
||||
jj.value(((JsonCanIntegerValue) v).value);
|
||||
else if (v instanceof JsonCanBooleanValue)
|
||||
gson.value(((JsonCanBooleanValue) v).value);
|
||||
jj.value(((JsonCanBooleanValue) v).value);
|
||||
else if (v instanceof JsonCanStringValue)
|
||||
gson.value(((JsonCanStringValue) v).value);
|
||||
jj.value(((JsonCanStringValue) v).value);
|
||||
else if (v instanceof JsonCanNullValue)
|
||||
gson.nullValue();
|
||||
jj.nullValue();
|
||||
else if (v instanceof JsonCanObject) {
|
||||
JsonCanObject o = (JsonCanObject) v;
|
||||
if (o.array)
|
||||
|
@ -188,7 +201,7 @@ public class JsonCreatorCanonical implements JsonCreator {
|
|||
} else
|
||||
throw new Error("not possible");
|
||||
}
|
||||
gson.endObject();
|
||||
jj.endObject();
|
||||
}
|
||||
|
||||
private JsonCanValue getPropForName(String name, List<JsonCanValue> children) {
|
||||
|
@ -199,18 +212,18 @@ public class JsonCreatorCanonical implements JsonCreator {
|
|||
}
|
||||
|
||||
private void writeArray(JsonCanObject arr) throws IOException {
|
||||
gson.beginArray();
|
||||
jj.beginArray();
|
||||
for (JsonCanValue v : arr.children) {
|
||||
if (v instanceof JsonCanNumberValue)
|
||||
gson.value(((JsonCanNumberValue) v).value);
|
||||
jj.value(((JsonCanNumberValue) v).value);
|
||||
else if (v instanceof JsonCanIntegerValue)
|
||||
gson.value(((JsonCanIntegerValue) v).value);
|
||||
jj.value(((JsonCanIntegerValue) v).value);
|
||||
else if (v instanceof JsonCanBooleanValue)
|
||||
gson.value(((JsonCanBooleanValue) v).value);
|
||||
jj.value(((JsonCanBooleanValue) v).value);
|
||||
else if (v instanceof JsonCanStringValue)
|
||||
gson.value(((JsonCanStringValue) v).value);
|
||||
jj.value(((JsonCanStringValue) v).value);
|
||||
else if (v instanceof JsonCanNullValue)
|
||||
gson.nullValue();
|
||||
jj.nullValue();
|
||||
else if (v instanceof JsonCanObject) {
|
||||
JsonCanObject o = (JsonCanObject) v;
|
||||
if (o.array)
|
||||
|
@ -220,7 +233,7 @@ public class JsonCreatorCanonical implements JsonCreator {
|
|||
} else
|
||||
throw new Error("not possible");
|
||||
}
|
||||
gson.endArray();
|
||||
jj.endArray();
|
||||
}
|
||||
|
||||
@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
|
||||
}
|
||||
|
||||
@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