From b404c89aa9e33c88fdb79ddb2707a0b86b432a84 Mon Sep 17 00:00:00 2001 From: dotasek Date: Fri, 23 Dec 2022 09:27:42 -0500 Subject: [PATCH] Profile Utilities Refactor 2 (#1047) * Add test util for diff * Start moving pathprocessor params into dedicated object * Move diff to Params * Move base and diff Limits to params * Rename to newBaseCursor and newBaseLimit * More renames * Move url and webUrl to params * Move profileName to params * Add contextPathSource to params, adjust indent for processPaths calls * Move contextPathTarget to params * Code cleanup, unused variables + move trimDifferential to params * Create PathSlicingParams * Shuffle param order * Move redirector to params * Move sourceStructureDefinition to params * Move derived to params * Move debug statements to dedicated methods * split processSimplePath * split processPathWithSlicedBase * Start splitting ProfilePathProcessor * Move all params into ProfilePathProcessor * Move all profile utility related classes to own package Co-authored-by: dotasek --- .../ElementDefinition10_50.java | 2 +- .../ElementDefinition14_50.java | 2 +- .../loaders/loaderR5/R2016MayToR5Loader.java | 2 +- org.hl7.fhir.r5/pom.xml | 6 + .../r5/comparison/ComparisonRenderer.java | 2 +- .../fhir/r5/comparison/ComparisonSession.java | 5 +- .../fhir/r5/comparison/ProfileComparer.java | 5 +- .../AdditionalBindingsRenderer.java | 8 +- .../r5/conformance/ProfilePathProcessor.java | 1045 ------------- .../fhir/r5/conformance/ShExGenerator.java | 57 +- .../r5/conformance/XmlSchemaGenerator.java | 57 +- .../{ => profile}/BaseTypeSlice.java | 2 +- .../profile/PathSlicingParams.java | 22 + .../profile/ProfilePathProcessor.java | 1290 +++++++++++++++++ .../profile/ProfilePathProcessorState.java | 17 + .../{ => profile}/ProfileUtilities.java | 13 +- .../conformance/{ => profile}/TypeSlice.java | 2 +- .../fhir/r5/context/BaseWorkerContext.java | 9 +- .../hl7/fhir/r5/context/ContextUtilities.java | 4 +- .../fhir/r5/context/SimpleWorkerContext.java | 10 - .../org/hl7/fhir/r5/elementmodel/Element.java | 59 +- .../hl7/fhir/r5/elementmodel/JsonParser.java | 63 +- .../fhir/r5/elementmodel/ObjectConverter.java | 60 +- .../hl7/fhir/r5/elementmodel/Property.java | 62 +- .../fhir/r5/elementmodel/ResourceParser.java | 16 +- .../hl7/fhir/r5/elementmodel/XmlParser.java | 3 +- .../r5/renderers/utils/ElementWrappers.java | 3 - .../r5/renderers/utils/RenderingContext.java | 9 +- .../org/hl7/fhir/r5/utils/FHIRPathEngine.java | 4 +- .../fhir/r5/utils/GraphQLSchemaGenerator.java | 2 +- .../fhir/r5/utils/QuestionnaireBuilder.java | 2 +- .../structuremap/StructureMapUtilities.java | 4 +- .../test/java/org/hl7/fhir/r5/DiffUtils.java | 27 + .../r5/test/NarrativeGenerationTests.java | 5 +- .../fhir/r5/test/ProfileUtilitiesTests.java | 2 +- .../hl7/fhir/r5/test/ShexGeneratorTests.java | 2 +- .../fhir/r5/test/SnapShotGenerationTests.java | 13 +- .../hl7/fhir/validation/ValidationEngine.java | 2 +- .../instance/InstanceValidator.java | 4 +- .../type/StructureDefinitionValidator.java | 2 +- .../comparison/tests/ComparisonTests.java | 2 +- .../tests/SnapShotGenerationXTests.java | 4 +- .../validation/tests/ValidationTests.java | 6 +- 43 files changed, 1594 insertions(+), 1322 deletions(-) delete mode 100644 org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfilePathProcessor.java rename org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/{ => profile}/BaseTypeSlice.java (94%) create mode 100644 org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/PathSlicingParams.java create mode 100644 org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessor.java create mode 100644 org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessorState.java rename org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/{ => profile}/ProfileUtilities.java (99%) rename org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/{ => profile}/TypeSlice.java (89%) create mode 100644 org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/DiffUtils.java diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv10_50/datatypes10_50/ElementDefinition10_50.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv10_50/datatypes10_50/ElementDefinition10_50.java index 90d37e90d..869fcf552 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv10_50/datatypes10_50/ElementDefinition10_50.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv10_50/datatypes10_50/ElementDefinition10_50.java @@ -15,7 +15,7 @@ import org.hl7.fhir.convertors.conv10_50.datatypes10_50.primitivetypes10_50.Stri import org.hl7.fhir.convertors.conv10_50.resources10_50.Enumerations10_50; import org.hl7.fhir.dstu2.utils.ToolingExtensions; import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.r5.conformance.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.utilities.Utilities; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv14_50/datatypes14_50/ElementDefinition14_50.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv14_50/datatypes14_50/ElementDefinition14_50.java index c4a976c1f..481015ea7 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv14_50/datatypes14_50/ElementDefinition14_50.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv14_50/datatypes14_50/ElementDefinition14_50.java @@ -17,7 +17,7 @@ import org.hl7.fhir.convertors.conv14_50.datatypes14_50.primitivetypes14_50.Uri1 import org.hl7.fhir.convertors.conv14_50.resources14_50.Enumerations14_50; import org.hl7.fhir.dstu2016may.model.ElementDefinition; import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.r5.conformance.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.utilities.Utilities; public class ElementDefinition14_50 { diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R2016MayToR5Loader.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R2016MayToR5Loader.java index 136e296a8..fd1d5f576 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R2016MayToR5Loader.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R2016MayToR5Loader.java @@ -42,7 +42,7 @@ import org.hl7.fhir.dstu2016may.formats.JsonParser; import org.hl7.fhir.dstu2016may.formats.XmlParser; import org.hl7.fhir.dstu2016may.model.Resource; import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.r5.conformance.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.model.Bundle; import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r5.model.Bundle.BundleType; diff --git a/org.hl7.fhir.r5/pom.xml b/org.hl7.fhir.r5/pom.xml index 07419548c..2cce212b9 100644 --- a/org.hl7.fhir.r5/pom.xml +++ b/org.hl7.fhir.r5/pom.xml @@ -170,6 +170,12 @@ ${junit_jupiter_version} test + + io.github.java-diff-utils + java-diff-utils + 4.12 + test + diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonRenderer.java index 2b50e36cd..be29d518d 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonRenderer.java @@ -21,7 +21,7 @@ import org.hl7.fhir.r5.comparison.ResourceComparer.PlaceHolderComparison; import org.hl7.fhir.r5.comparison.ResourceComparer.ResourceComparison; import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison; -import org.hl7.fhir.r5.conformance.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.model.Base; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonSession.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonSession.java index b897f0647..13969d088 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonSession.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonSession.java @@ -13,8 +13,8 @@ import org.hl7.fhir.r5.comparison.CodeSystemComparer.CodeSystemComparison; import org.hl7.fhir.r5.comparison.ProfileComparer.ProfileComparison; import org.hl7.fhir.r5.comparison.ResourceComparer.ResourceComparison; import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison; -import org.hl7.fhir.r5.conformance.ProfileUtilities; -import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ProfileKnowledgeProvider; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.model.CanonicalResource; import org.hl7.fhir.r5.model.CapabilityStatement; @@ -22,7 +22,6 @@ import org.hl7.fhir.r5.model.CodeSystem; import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.ValueSet; -import org.hl7.fhir.utilities.Utilities; public class ComparisonSession { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ProfileComparer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ProfileComparer.java index 292bd1409..db4f81196 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ProfileComparer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ProfileComparer.java @@ -9,10 +9,9 @@ import java.util.List; import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; -import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts; import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison; -import org.hl7.fhir.r5.conformance.ProfileUtilities; -import org.hl7.fhir.r5.conformance.ProfileUtilities.UnusedTracker; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.UnusedTracker; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.formats.IParser; import org.hl7.fhir.r5.formats.JsonParser; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/AdditionalBindingsRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/AdditionalBindingsRenderer.java index 28528888d..035c4188f 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/AdditionalBindingsRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/AdditionalBindingsRenderer.java @@ -7,17 +7,15 @@ import java.util.List; import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRFormatError; -import org.hl7.fhir.r5.conformance.AdditionalBindingsRenderer.AdditionalBindingDetail; -import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider; -import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider.BindingResolution; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ProfileKnowledgeProvider; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ProfileKnowledgeProvider.BindingResolution; import org.hl7.fhir.r5.model.Extension; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.UsageContext; import org.hl7.fhir.r5.renderers.DataRenderer; import org.hl7.fhir.r5.renderers.IMarkdownProcessor; import org.hl7.fhir.r5.renderers.utils.RenderingContext; -import org.hl7.fhir.r5.utils.PublicationHacker; -import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator; import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Cell; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfilePathProcessor.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfilePathProcessor.java deleted file mode 100644 index 35b04999d..000000000 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfilePathProcessor.java +++ /dev/null @@ -1,1045 +0,0 @@ -package org.hl7.fhir.r5.conformance; - -import org.hl7.fhir.exceptions.DefinitionException; -import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.r5.model.CanonicalType; -import org.hl7.fhir.r5.model.ElementDefinition; -import org.hl7.fhir.r5.model.StructureDefinition; -import org.hl7.fhir.r5.utils.ToolingExtensions; -import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.i18n.I18nConstants; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -public class ProfilePathProcessor { - - private final ProfileUtilities profileUtilities; - - public class ProfilePathProcessorCursors { - private StructureDefinition.StructureDefinitionSnapshotComponent base; - - private int baseCursor; - private int diffCursor; - - private String contextName; - private String resultPathBase; - - public ProfilePathProcessorCursors( - StructureDefinition.StructureDefinitionSnapshotComponent base, - - int baseCursor, - int diffCursor, - - String contextName, - String resultPathBase - ) { - this.base = base; - - this.baseCursor = baseCursor; - this.diffCursor = diffCursor; - - this.contextName = contextName; - this.resultPathBase = resultPathBase; - } - - } - - - public ProfilePathProcessor(ProfileUtilities profileUtilities) { - this.profileUtilities = profileUtilities; - } - - protected void processPaths(StructureDefinition base, StructureDefinition derived, String url, String webUrl, StructureDefinition.StructureDefinitionDifferentialComponent diff, StructureDefinition.StructureDefinitionSnapshotComponent baseSnapshot) { - - ProfilePathProcessorCursors cursors = new ProfilePathProcessorCursors( - baseSnapshot, - 0, - 0, - base.getUrl(), - null); - - processPaths("", derived.getSnapshot(), diff, baseSnapshot.getElement().size() - 1, derived.getDifferential().hasElement() ? derived.getDifferential().getElement().size() - 1 : -1, url, webUrl, derived.present(), null, null, false, false, null, null, new ArrayList(), base, - derived, cursors); - } - - /** - * @param trimDifferential - * @param srcSD - * @param derived - * @param cursors - * @throws DefinitionException, FHIRException - * @throws Exception - */ - private ElementDefinition processPaths(final String indent, - final StructureDefinition.StructureDefinitionSnapshotComponent result, - final StructureDefinition.StructureDefinitionDifferentialComponent differential, final int baseLimit, final int diffLimit, final String url, final String webUrl, final String profileName, final String contextPathSrc, final String contextPathDst, final boolean trimDifferential, final boolean slicingDone, final ElementDefinition slicer, final String typeSlicingPath, final List redirector, final StructureDefinition srcSD, - StructureDefinition derived, ProfilePathProcessorCursors cursors) throws FHIRException { - if (profileUtilities.isDebug()) { - System.out.println(indent + "PP @ " + cursors.resultPathBase + " / " + contextPathSrc + " : base = " + cursors.baseCursor + " to " + baseLimit + ", diff = " + cursors.diffCursor + " to " + diffLimit + " (slicing = " + slicingDone + ", k " + (redirector == null ? "null" : redirector.toString()) + ")"); - } - ElementDefinition res = null; - List typeList = new ArrayList<>(); - // just repeat processing entries until we run out of our allowed scope (1st entry, the allowed scope is all the entries) - while (cursors.baseCursor <= baseLimit) { - // get the current focus of the base, and decide what to do - ElementDefinition currentBase = cursors.base.getElement().get(cursors.baseCursor); - String currentBasePath = profileUtilities.fixedPathSource(contextPathSrc, currentBase.getPath(), redirector); - if (profileUtilities.isDebug()) { - System.out.println(indent + " - " + currentBasePath + ": base = " + cursors.baseCursor + " (" + profileUtilities.descED(cursors.base.getElement(), cursors.baseCursor) + ") to " + baseLimit + " (" + profileUtilities.descED(cursors.base.getElement(), baseLimit) + "), diff = " + cursors.diffCursor + " (" + profileUtilities.descED(differential.getElement(), cursors.diffCursor) + ") to " + diffLimit + " (" + profileUtilities.descED(differential.getElement(), diffLimit) + ") " + - "(slicingDone = " + slicingDone + ") (diffpath= " + (differential.getElement().size() > cursors.diffCursor ? differential.getElement().get(cursors.diffCursor).getPath() : "n/a") + ")"); - } - List diffMatches = profileUtilities.getDiffMatches(differential, currentBasePath, cursors.diffCursor, diffLimit, profileName); // get a list of matching elements in scope - - // in the simple case, source is not sliced. - if (!currentBase.hasSlicing() || currentBasePath.equals(typeSlicingPath)) - { - ElementDefinition currentRes = processSimplePath(currentBase, currentBasePath, diffMatches, typeList, - indent, - result, - differential, baseLimit, diffLimit, url, webUrl, profileName, contextPathSrc, contextPathDst, trimDifferential, slicingDone, slicer, typeSlicingPath, redirector, srcSD, - derived, cursors - ); - if (res == null) { - res = currentRes; - } - } - else { - processPathWithSlicedBase(currentBase, currentBasePath, diffMatches, typeList, - indent, - result, - differential, baseLimit, diffLimit, url, webUrl, profileName, contextPathSrc, contextPathDst, trimDifferential, slicingDone, slicer, typeSlicingPath, redirector, srcSD, - derived, cursors - ); - } - } - - int i = 0; - for (ElementDefinition e : result.getElement()) { - i++; - if (e.hasMinElement() && e.getMinElement().getValue() == null) - throw new Error(profileUtilities.getContext().formatMessage(I18nConstants.NULL_MIN)); - } - return res; - } - - - public ElementDefinition processSimplePath( - ElementDefinition currentBase, - String currentBasePath, - List diffMatches, - List typeList, - final String indent, - final StructureDefinition.StructureDefinitionSnapshotComponent result, - final StructureDefinition.StructureDefinitionDifferentialComponent differential, final int baseLimit, final int diffLimit, final String url, final String webUrl, final String profileName, final String contextPathSrc, final String contextPathDst, final boolean trimDifferential, final boolean slicingDone, final ElementDefinition slicer, final String typeSlicingPath, final List redirector, final StructureDefinition srcSD, - StructureDefinition derived, ProfilePathProcessorCursors cursors) throws FHIRException { - ElementDefinition res = null; - - // the differential doesn't say anything about this item - // so we just copy it in - if (diffMatches.isEmpty()) { - ElementDefinition outcome = profileUtilities.updateURLs(url, webUrl, currentBase.copy()); - outcome.setPath(profileUtilities.fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); - profileUtilities.updateFromBase(outcome, currentBase, srcSD.getUrl()); - profileUtilities.updateConstraintSources(outcome, srcSD.getUrl()); - profileUtilities.markDerived(outcome); - if (cursors.resultPathBase == null) - cursors.resultPathBase = outcome.getPath(); - else if (!outcome.getPath().startsWith(cursors.resultPathBase)) - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH__OUTCOMEGETPATH___RESULTPATHBASE__, outcome.getPath(), cursors.resultPathBase)); - result.getElement().add(outcome); - if (profileUtilities.hasInnerDiffMatches(differential, currentBasePath, cursors.diffCursor, diffLimit, cursors.base.getElement(), true)) { - // well, the profile walks into this, so we need to as well - // did we implicitly step into a new type? - if (profileUtilities.baseHasChildren(cursors.base, currentBase)) { // not a new type here - processPaths(indent + " ", result, differential, baseLimit, diffLimit, url, webUrl, profileName, contextPathSrc, contextPathDst, trimDifferential, false, null, null, redirector, srcSD, derived, new ProfilePathProcessorCursors(cursors.base, cursors.baseCursor + 1, cursors.diffCursor, cursors.contextName, cursors.resultPathBase)); - cursors.baseCursor = profileUtilities.indexOfFirstNonChild(cursors.base, currentBase, cursors.baseCursor + 1, baseLimit); - } else { - if (outcome.getType().size() == 0 && !outcome.hasContentReference()) { - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants._HAS_NO_CHILDREN__AND_NO_TYPES_IN_PROFILE_, currentBasePath, differential.getElement().get(cursors.diffCursor).getPath(), profileName)); - } - boolean nonExtension = false; - if (outcome.getType().size() > 1) { - for (ElementDefinition.TypeRefComponent t : outcome.getType()) { - if (!t.getWorkingCode().equals("Reference")) { - for (ElementDefinition ed : diffMatches) { - if (ed != diffMatches.get(0) && !ed.getPath().endsWith(".extension")) { - nonExtension = true; - } - } - } - } - } - int start = cursors.diffCursor; - while (differential.getElement().size() > cursors.diffCursor && profileUtilities.pathStartsWith(differential.getElement().get(cursors.diffCursor).getPath(), currentBasePath + ".")) - cursors.diffCursor++; - if (nonExtension) { - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants._HAS_CHILDREN__AND_MULTIPLE_TYPES__IN_PROFILE_, currentBasePath, differential.getElement().get(cursors.diffCursor).getPath(), profileUtilities.typeCode(outcome.getType()), profileName)); - } - if (outcome.hasContentReference()) { - ProfileUtilities.ElementDefinitionResolution tgt = profileUtilities.getElementById(srcSD, cursors.base.getElement(), outcome.getContentReference()); - if (tgt == null) - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.UNABLE_TO_RESOLVE_REFERENCE_TO_, outcome.getContentReference())); - profileUtilities.replaceFromContentReference(outcome, tgt.getElement()); - if (tgt.getSource() != srcSD) { - cursors.base = tgt.getSource().getSnapshot(); - int nbc = cursors.base.getElement().indexOf(tgt.getElement()) + 1; - int nbl = nbc; - while (nbl < cursors.base.getElement().size() && cursors.base.getElement().get(nbl).getPath().startsWith(tgt.getElement().getPath() + ".")) - nbl++; - processPaths(indent + " ", result, differential, nbl - 1, cursors.diffCursor - 1, url, webUrl, profileName, tgt.getElement().getPath(), diffMatches.get(0).getPath(), trimDifferential, false, null, null, profileUtilities.redirectorStack(redirector, outcome, currentBasePath), tgt.getSource(), derived, new ProfilePathProcessorCursors(cursors.base, nbc, start - 1, cursors.contextName, cursors.resultPathBase)); - } else { - int nbc = cursors.base.getElement().indexOf(tgt.getElement()) + 1; - int nbl = nbc; - while (nbl < cursors.base.getElement().size() && cursors.base.getElement().get(nbl).getPath().startsWith(tgt.getElement().getPath() + ".")) - nbl++; - System.out.println("Test!"); - processPaths(indent + " ", result, differential, nbl - 1, cursors.diffCursor - 1, url, webUrl, profileName, tgt.getElement().getPath(), outcome.getPath(), trimDifferential, false, null, null, profileUtilities.redirectorStack(redirector, outcome, currentBasePath), srcSD, derived, new ProfilePathProcessorCursors(cursors.base, nbc, start, cursors.contextName, cursors.resultPathBase)); - } - } else { - StructureDefinition dt = outcome.getType().size() > 1 ? profileUtilities.getContext().fetchTypeDefinition("Element") : profileUtilities.getProfileForDataType(outcome.getType().get(0), webUrl, derived); - if (dt == null) { - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.UNKNOWN_TYPE__AT_, outcome.getType().get(0), currentBasePath)); - } - cursors.contextName = dt.getUrl(); - if (redirector == null || redirector.isEmpty()) { - processPaths(indent + " ", result, differential, dt.getSnapshot().getElement().size() - 1, cursors.diffCursor - 1, url, profileUtilities.getWebUrl(dt, webUrl, indent), profileName, currentBasePath, outcome.getPath(), trimDifferential, false, null, null, redirector, srcSD, /* starting again on the data type, but skip the root */ - derived, new ProfilePathProcessorCursors(dt.getSnapshot(), 1 /* starting again on the data type, but skip the root */, start, - cursors.contextName, cursors.resultPathBase)); - } else { - processPaths(indent + " ", result, differential, dt.getSnapshot().getElement().size() - 1, cursors.diffCursor - 1, url, profileUtilities.getWebUrl(dt, webUrl, indent), profileName, currentBasePath, outcome.getPath(), trimDifferential, false, null, null, profileUtilities.redirectorStack(redirector, currentBase, currentBasePath), srcSD, /* starting again on the data type, but skip the root */ - derived, new ProfilePathProcessorCursors(dt.getSnapshot(), 1 /* starting again on the data type, but skip the root */, start, - cursors.contextName, cursors.resultPathBase)); - } - } - } - } - cursors.baseCursor++; - } - // one matching element in the differential - else if (oneMatchingElementInDifferential(slicingDone, currentBasePath, diffMatches) - ) { - ElementDefinition template = null; - if (diffMatches.get(0).hasType() && "Reference".equals(diffMatches.get(0).getType().get(0).getWorkingCode()) && !profileUtilities.isValidType(diffMatches.get(0).getType().get(0), currentBase)) { - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.VALIDATION_VAL_ILLEGAL_TYPE_CONSTRAINT, url, diffMatches.get(0).getPath(), diffMatches.get(0).getType().get(0), currentBase.typeSummary())); - } - String id = diffMatches.get(0).getId(); - String lid = profileUtilities.tail(id); - if (lid.contains("/")) { - // the template comes from the snapshot of the base - profileUtilities.generateIds(result.getElement(), url, srcSD.getType(), srcSD); - String baseId = id.substring(0, id.length() - lid.length()) + lid.substring(0, lid.indexOf("/")); // this is wrong if there's more than one reslice (todo: one thing at a time) - template = profileUtilities.getById(result.getElement(), baseId); - - } else if (diffMatches.get(0).hasType() - && diffMatches.get(0).getType().size() == 1 - && diffMatches.get(0).getType().get(0).hasProfile() - && !"Reference".equals(diffMatches.get(0).getType().get(0).getWorkingCode())) { - CanonicalType firstTypeProfile = diffMatches.get(0).getType().get(0).getProfile().get(0); - StructureDefinition firstTypeStructureDefinition = profileUtilities.getContext().fetchResource(StructureDefinition.class, firstTypeProfile.getValue()); - if (firstTypeStructureDefinition == null && profileUtilities.getXver() != null && profileUtilities.getXver().matchingUrl(firstTypeProfile.getValue())) { - switch (profileUtilities.getXver().status(firstTypeProfile.getValue())) { - case BadVersion: - throw new FHIRException("Reference to invalid version in extension url " + firstTypeProfile.getValue()); - case Invalid: - throw new FHIRException("Reference to invalid extension " + firstTypeProfile.getValue()); - case Unknown: - throw new FHIRException("Reference to unknown extension " + firstTypeProfile.getValue()); - case Valid: - firstTypeStructureDefinition = profileUtilities.getXver().makeDefinition(firstTypeProfile.getValue()); - profileUtilities.generateSnapshot(profileUtilities.getContext().fetchTypeDefinition("Extension"), firstTypeStructureDefinition, firstTypeStructureDefinition.getUrl(), webUrl, firstTypeStructureDefinition.getName()); - } - } - if (firstTypeStructureDefinition != null) { - if (!profileUtilities.isMatchingType(firstTypeStructureDefinition, diffMatches.get(0).getType(), firstTypeProfile.getExtensionString(ToolingExtensions.EXT_PROFILE_ELEMENT))) { - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.VALIDATION_VAL_PROFILE_WRONGTYPE2, firstTypeStructureDefinition.getUrl(), diffMatches.get(0).getPath(), firstTypeStructureDefinition.getType(), firstTypeProfile.getValue(), diffMatches.get(0).getType().get(0).getWorkingCode())); - } - if (profileUtilities.isGenerating(firstTypeStructureDefinition)) { - // this is a special case, because we're only going to access the first element, and we can rely on the fact that it's already populated. - // but we check anyway - if (firstTypeStructureDefinition.getSnapshot().getElementFirstRep().isEmpty()) { - throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ATTEMPT_TO_USE_A_SNAPSHOT_ON_PROFILE__AS__BEFORE_IT_IS_GENERATED, firstTypeStructureDefinition.getUrl(), "Source for first element")); - } - } else if (!firstTypeStructureDefinition.hasSnapshot()) { - StructureDefinition sdb = profileUtilities.getContext().fetchResource(StructureDefinition.class, firstTypeStructureDefinition.getBaseDefinition()); - if (sdb == null) - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.UNABLE_TO_FIND_BASE__FOR_, firstTypeStructureDefinition.getBaseDefinition(), firstTypeStructureDefinition.getUrl())); - profileUtilities.checkNotGenerating(sdb, "an extension base"); - profileUtilities.generateSnapshot(sdb, firstTypeStructureDefinition, firstTypeStructureDefinition.getUrl(), (sdb.hasUserData("path")) ? Utilities.extractBaseUrl(sdb.getUserString("path")) : webUrl, firstTypeStructureDefinition.getName()); - } - ElementDefinition src; - if (firstTypeProfile.hasExtension(ToolingExtensions.EXT_PROFILE_ELEMENT)) { - src = null; - String eid = firstTypeProfile.getExtensionString(ToolingExtensions.EXT_PROFILE_ELEMENT); - for (ElementDefinition t : firstTypeStructureDefinition.getSnapshot().getElement()) { - if (eid.equals(t.getId())) - src = t; - } - if (src == null) - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.UNABLE_TO_FIND_ELEMENT__IN_, eid, firstTypeProfile.getValue())); - } else - src = firstTypeStructureDefinition.getSnapshot().getElement().get(0); - template = src.copy().setPath(currentBase.getPath()); - template.setSliceName(null); - // temporary work around - if (!"Extension".equals(diffMatches.get(0).getType().get(0).getCode())) { - template.setMin(currentBase.getMin()); - template.setMax(currentBase.getMax()); - } - } - } - if (template == null) - template = currentBase.copy(); - else - // some of what's in currentBase overrides template - template = profileUtilities.fillOutFromBase(template, currentBase); - - ElementDefinition outcome = profileUtilities.updateURLs(url, webUrl, template); - outcome.setPath(profileUtilities.fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); - if (res == null) - res = outcome; - profileUtilities.updateFromBase(outcome, currentBase, srcSD.getUrl()); - if (diffMatches.get(0).hasSliceName()) { - outcome.setSliceName(diffMatches.get(0).getSliceName()); - if (!diffMatches.get(0).hasMin() && (diffMatches.size() > 1 || slicer == null || slicer.getSlicing().getRules() != ElementDefinition.SlicingRules.CLOSED) && !currentBase.hasSliceName()) { - if (!currentBasePath.endsWith("xtension.value[x]")) { // hack work around for problems with snapshots in official releases - outcome.setMin(0); - } - } - } - profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), profileName, trimDifferential, url, srcSD, derived); - profileUtilities.removeStatusExtensions(outcome); -// if (outcome.getPath().endsWith("[x]") && outcome.getType().size() == 1 && !outcome.getType().get(0).getCode().equals("*") && !diffMatches.get(0).hasSlicing()) // if the base profile allows multiple types, but the profile only allows one, rename it -// outcome.setPath(outcome.getPath().substring(0, outcome.getPath().length()-3)+Utilities.capitalize(outcome.getType().get(0).getCode())); - outcome.setSlicing(null); - if (cursors.resultPathBase == null) - cursors.resultPathBase = outcome.getPath(); - else if (!outcome.getPath().startsWith(cursors.resultPathBase)) - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH)); - result.getElement().add(outcome); - cursors.baseCursor++; - cursors.diffCursor = differential.getElement().indexOf(diffMatches.get(0)) + 1; - if (diffLimit >= cursors.diffCursor && outcome.getPath().contains(".") && (profileUtilities.isDataType(outcome.getType()) || profileUtilities.isBaseResource(outcome.getType()) || outcome.hasContentReference())) { // don't want to do this for the root, since that's base, and we're already processing it - if (profileUtilities.pathStartsWith(differential.getElement().get(cursors.diffCursor).getPath(), diffMatches.get(0).getPath() + ".") && !profileUtilities.baseWalksInto(cursors.base.getElement(), cursors.baseCursor)) { - if (outcome.getType().size() > 1) { - if (outcome.getPath().endsWith("[x]") && !diffMatches.get(0).getPath().endsWith("[x]")) { - String en = profileUtilities.tail(outcome.getPath()); - String tn = profileUtilities.tail(diffMatches.get(0).getPath()); - String t = tn.substring(en.length() - 3); - if (profileUtilities.isPrimitive(Utilities.uncapitalize(t))) - t = Utilities.uncapitalize(t); - List ntr = profileUtilities.getByTypeName(outcome.getType(), t); // keep any additional information - if (ntr.isEmpty()) - ntr.add(new ElementDefinition.TypeRefComponent().setCode(t)); - outcome.getType().clear(); - outcome.getType().addAll(ntr); - } - if (outcome.getType().size() > 1) - for (ElementDefinition.TypeRefComponent t : outcome.getType()) { - if (!t.getCode().equals("Reference")) { - boolean nonExtension = false; - for (ElementDefinition ed : diffMatches) - if (ed != diffMatches.get(0) && !ed.getPath().endsWith(".extension")) - nonExtension = true; - if (nonExtension) - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants._HAS_CHILDREN__AND_MULTIPLE_TYPES__IN_PROFILE_, diffMatches.get(0).getPath(), differential.getElement().get(cursors.diffCursor).getPath(), profileUtilities.typeCode(outcome.getType()), profileName)); - } - } - } - int start = cursors.diffCursor; - while (cursors.diffCursor <= diffLimit && differential.getElement().size() > cursors.diffCursor && profileUtilities.pathStartsWith(differential.getElement().get(cursors.diffCursor).getPath(), diffMatches.get(0).getPath() + ".")) - cursors.diffCursor++; - if (outcome.hasContentReference()) { - ProfileUtilities.ElementDefinitionResolution tgt = profileUtilities.getElementById(srcSD, cursors.base.getElement(), outcome.getContentReference()); - if (tgt == null) - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.UNABLE_TO_RESOLVE_REFERENCE_TO_, outcome.getContentReference())); - profileUtilities.replaceFromContentReference(outcome, tgt.getElement()); - if (tgt.getSource() != srcSD) { - cursors.base = tgt.getSource().getSnapshot(); - int nbc = cursors.base.getElement().indexOf(tgt.getElement()) + 1; - int nbl = nbc; - while (nbl < cursors.base.getElement().size() && cursors.base.getElement().get(nbl).getPath().startsWith(tgt.getElement().getPath() + ".")) - nbl++; - processPaths(indent + " ", result, differential, nbl - 1, cursors.diffCursor - 1, url, webUrl, profileName, tgt.getElement().getPath(), diffMatches.get(0).getPath(), trimDifferential, false, null, null, profileUtilities.redirectorStack(redirector, outcome, currentBasePath), tgt.getSource(), derived, new ProfilePathProcessorCursors(cursors.base, nbc, start - 1, cursors.contextName, cursors.resultPathBase)); - } else { - int nbc = cursors.base.getElement().indexOf(tgt.getElement()) + 1; - int nbl = nbc; - while (nbl < cursors.base.getElement().size() && cursors.base.getElement().get(nbl).getPath().startsWith(tgt.getElement().getPath() + ".")) - nbl++; - processPaths(indent + " ", result, differential, nbl - 1, cursors.diffCursor - 1, url, webUrl, profileName, tgt.getElement().getPath(), diffMatches.get(0).getPath(), trimDifferential, false, null, null, profileUtilities.redirectorStack(redirector, outcome, currentBasePath), srcSD, derived, new ProfilePathProcessorCursors(cursors.base, nbc, start - 1, cursors.contextName, cursors.resultPathBase)); - } - } else { - StructureDefinition dt = outcome.getType().size() == 1 ? profileUtilities.getProfileForDataType(outcome.getType().get(0), webUrl, derived) : profileUtilities.getProfileForDataType("Element"); - if (dt == null) - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants._HAS_CHILDREN__FOR_TYPE__IN_PROFILE__BUT_CANT_FIND_TYPE, diffMatches.isEmpty() ? "??" : diffMatches.get(0).getPath(), differential.getElement().get(cursors.diffCursor).getPath(), profileUtilities.typeCode(outcome.getType()), profileName)); - cursors.contextName = dt.getUrl(); - processPaths(indent + " ", result, differential, dt.getSnapshot().getElement().size() - 1, cursors.diffCursor - 1, url, profileUtilities.getWebUrl(dt, webUrl, indent), profileName + profileUtilities.pathTail(diffMatches, 0), diffMatches.get(0).getPath(), outcome.getPath(), trimDifferential, false, null, null, new ArrayList(), srcSD, /* starting again on the data type, but skip the root */ - derived, new ProfilePathProcessorCursors(dt.getSnapshot(), 1 /* starting again on the data type, but skip the root */, start, - cursors.contextName, cursors.resultPathBase)); - } - } - } - } else if (profileUtilities.diffsConstrainTypes(diffMatches, currentBasePath, typeList)) { - int start = 0; - int nbl = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor); - int ndc = differential.getElement().indexOf(diffMatches.get(0)); - ElementDefinition elementToRemove = null; - boolean shortCut = !typeList.isEmpty() && typeList.get(0).getType() != null; - // we come here whether they are sliced in the diff, or whether the short cut is used. - if (shortCut) { - // this is the short cut method, we've just dived in and specified a type slice. - // in R3 (and unpatched R4, as a workaround right now... - if (!VersionUtilities.isR4Plus(profileUtilities.getContext().getVersion()) || !profileUtilities.isNewSlicingProcessing()) { // newSlicingProcessing is a work around for editorial loop dependency - // we insert a cloned element with the right types at the start of the diffMatches - ElementDefinition ed = new ElementDefinition(); - ed.setPath(profileUtilities.determineTypeSlicePath(diffMatches.get(0).getPath(), currentBasePath)); - for (TypeSlice ts : typeList) - ed.addType().setCode(ts.getType()); - ed.setSlicing(new ElementDefinition.ElementDefinitionSlicingComponent()); - ed.getSlicing().addDiscriminator().setType(ElementDefinition.DiscriminatorType.TYPE).setPath("$this"); - ed.getSlicing().setRules(ElementDefinition.SlicingRules.CLOSED); - ed.getSlicing().setOrdered(false); - diffMatches.add(0, ed); - differential.getElement().add(ndc, ed); - elementToRemove = ed; - } else { - // as of R4, this changed; if there's no slice, there's no constraint on the slice types, only one the type. - // so the element we insert specifies no types (= all types) allowed in the base, not just the listed type. - // see also discussion here: https://chat.fhir.org/#narrow/stream/179177-conformance/topic/Slicing.20a.20non-repeating.20element - ElementDefinition ed = new ElementDefinition(); - ed.setPath(profileUtilities.determineTypeSlicePath(diffMatches.get(0).getPath(), currentBasePath)); - ed.setSlicing(new ElementDefinition.ElementDefinitionSlicingComponent()); - ed.getSlicing().addDiscriminator().setType(ElementDefinition.DiscriminatorType.TYPE).setPath("$this"); - ed.getSlicing().setRules(ElementDefinition.SlicingRules.CLOSED); - ed.getSlicing().setOrdered(false); - diffMatches.add(0, ed); - differential.getElement().add(ndc, ed); - elementToRemove = ed; - } - } - int ndl = profileUtilities.findEndOfElement(differential, ndc); - // the first element is setting up the slicing - - if (diffMatches.get(0).getSlicing().hasOrdered()) { - if (diffMatches.get(0).getSlicing().getOrdered()) { - throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGORDERED__TRUE, currentBasePath, url)); - } - } - if (diffMatches.get(0).getSlicing().hasDiscriminator()) { - if (diffMatches.get(0).getSlicing().getDiscriminator().size() != 1) { - throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORCOUNT__1, currentBasePath, url)); - } - if (diffMatches.get(0).getSlicing().getDiscriminatorFirstRep().getType() != ElementDefinition.DiscriminatorType.TYPE) { - throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORTYPE__TYPE, currentBasePath, url)); - } - if (!"$this".equals(diffMatches.get(0).getSlicing().getDiscriminatorFirstRep().getPath())) { - throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORPATH__THIS, currentBasePath, url)); - } - } - // check the slice names too while we're at it... - for (TypeSlice ts : typeList) { - if (ts.getType() != null) { - String tn = profileUtilities.rootName(currentBasePath) + Utilities.capitalize(ts.getType()); - if (!ts.defn.hasSliceName()) { - ts.defn.setSliceName(tn); - } else if (!ts.defn.getSliceName().equals(tn)) { - if (profileUtilities.isAutoFixSliceNames()) { - ts.defn.setSliceName(tn); - } else { - throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_NAME_MUST_BE__BUT_IS_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : currentBasePath), tn, ts.defn.getSliceName())); - } - } - if (!ts.defn.hasType()) { - ts.defn.addType().setCode(ts.type); - } else if (ts.defn.getType().size() > 1) { - throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_MORE_THAN_ONE_TYPE_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : currentBasePath), tn, ts.defn.typeSummary())); - } else if (!ts.defn.getType().get(0).getCode().equals(ts.type)) { - throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_WRONG_TYPE_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : currentBasePath), tn, ts.defn.typeSummary())); - } - } - } - - // ok passed the checks. - // copy the root diff, and then process any children it has - ElementDefinition e = processPaths(indent + " ", result, differential, nbl, ndl, url, webUrl, profileName + profileUtilities.pathTail(diffMatches, 0), contextPathSrc, contextPathDst, trimDifferential, true, null, null, redirector, srcSD, - derived, new ProfilePathProcessorCursors(cursors.base, cursors.baseCursor, ndc, - cursors.contextName, cursors.resultPathBase)); - if (e == null) - throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.DID_NOT_FIND_TYPE_ROOT_, diffMatches.get(0).getPath())); - // now set up slicing on the e (cause it was wiped by what we called. - e.setSlicing(new ElementDefinition.ElementDefinitionSlicingComponent()); - e.getSlicing().addDiscriminator().setType(ElementDefinition.DiscriminatorType.TYPE).setPath("$this"); - e.getSlicing().setRules(ElementDefinition.SlicingRules.CLOSED); // type slicing is always closed; the differential might call it open, but that just means it's not constraining the slices it doesn't mention - e.getSlicing().setOrdered(false); - - start++; - - String fixedType = null; - // now process the siblings, which should each be type constrained - and may also have their own children - // now we process the base scope repeatedly for each instance of the item in the differential list - for (int i = start; i < diffMatches.size(); i++) { - // our processing scope for the differential is the item in the list, and all the items before the next one in the list - if (diffMatches.get(i).getMin() > 0) { - if (diffMatches.size() > i + 1) { - throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.INVALID_SLICING__THERE_IS_MORE_THAN_ONE_TYPE_SLICE_AT__BUT_ONE_OF_THEM__HAS_MIN__1_SO_THE_OTHER_SLICES_CANNOT_EXIST, diffMatches.get(i).getPath(), diffMatches.get(i).getSliceName())); - } else { - e.setMin(1); - } - fixedType = profileUtilities.determineFixedType(diffMatches, fixedType, i); - } - ndc = differential.getElement().indexOf(diffMatches.get(i)); - ndl = profileUtilities.findEndOfElement(differential, ndc); - ElementDefinition typeSliceElement = processPaths(indent + " ", result, differential, nbl, ndl, url, webUrl, profileName + profileUtilities.pathTail(diffMatches, i), contextPathSrc, contextPathDst, trimDifferential, true, e, null, redirector, srcSD, derived, new ProfilePathProcessorCursors(cursors.base, cursors.baseCursor, ndc, cursors.contextName, cursors.resultPathBase)); - if (typeList.size() > start + 1) { - typeSliceElement.setMin(0); - } - } - if (elementToRemove != null) { - differential.getElement().remove(elementToRemove); - ndl--; - } - if (fixedType != null) { - for (Iterator iter = e.getType().iterator(); iter.hasNext(); ) { - ElementDefinition.TypeRefComponent tr = iter.next(); - if (!tr.getCode().equals(fixedType)) { - iter.remove(); - } - } - } - if (!"0".equals(e.getMax())) { - // check that there's a slice for each allowed types - Set allowedTypes = profileUtilities.getListOfTypes(e); - for (TypeSlice t : typeList) { - if (t.type != null) { - allowedTypes.remove(t.type); - } else if (t.getDefn().hasSliceName() && t.getDefn().getType().size() == 1) { - allowedTypes.remove(t.getDefn().getType().get(0).getCode()); - } - } - if (!allowedTypes.isEmpty()) { - if (currentBasePath.contains("xtension.value")) { - for (Iterator iter = e.getType().iterator(); iter.hasNext(); ) { - ElementDefinition.TypeRefComponent tr = iter.next(); - if (allowedTypes.contains(tr.getCode())) { - iter.remove(); - } - } -// System.out.println("!!: Extension Error at "+cpath+": Allowed Types not sliced = "+allowedTypes+". !Extension!!"); -// throw new Error("Extension Error at "+cpath+": Allowed Types not sliced = "+allowedTypes+". !Extension!!"); - - } else { - e.getSlicing().setRules(ElementDefinition.SlicingRules.OPEN); - } - } - } - // ok, done with that - next in the base list - cursors.baseCursor = nbl + 1; - cursors.diffCursor = ndl + 1; - - } else { - // ok, the differential slices the item. Let's check our pre-conditions to ensure that this is correct - if (!profileUtilities.unbounded(currentBase) && !profileUtilities.isSlicedToOneOnly(diffMatches.get(0))) - // you can only slice an element that doesn't repeat if the sum total of your slices is limited to 1 - // (but you might do that in order to split up constraints by type) - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ATTEMPT_TO_A_SLICE_AN_ELEMENT_THAT_DOES_NOT_REPEAT__FROM__IN_, currentBase.getPath(), currentBase.getPath(), cursors.contextName, url, diffMatches.get(0).getId(), profileUtilities.sliceNames(diffMatches))); - if (!diffMatches.get(0).hasSlicing() && !profileUtilities.isExtension(currentBase)) // well, the diff has set up a slice, but hasn't defined it. this is an error - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.DIFFERENTIAL_DOES_NOT_HAVE_A_SLICE__B_OF_____IN_PROFILE_, currentBase.getPath(), cursors.baseCursor, baseLimit, cursors.diffCursor, diffLimit, url, currentBasePath)); - - // well, if it passed those preconditions then we slice the dest. - int start = 0; - int nbl = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor); -// if (diffMatches.size() > 1 && diffMatches.get(0).hasSlicing() && differential.getElement().indexOf(diffMatches.get(1)) > differential.getElement().indexOf(diffMatches.get(0))+1) { - ElementDefinition slicerElement; - if (diffMatches.size() > 1 && diffMatches.get(0).hasSlicing() && (nbl > cursors.baseCursor || differential.getElement().indexOf(diffMatches.get(1)) > differential.getElement().indexOf(diffMatches.get(0)) + 1)) { // there's a default set before the slices - int ndc = differential.getElement().indexOf(diffMatches.get(0)); - int ndl = profileUtilities.findEndOfElement(differential, ndc); - ElementDefinition e = processPaths(indent + " ", result, differential, nbl, ndl, url, webUrl, profileName + profileUtilities.pathTail(diffMatches, 0), contextPathSrc, contextPathDst, trimDifferential, true, null, null, redirector, srcSD, - derived, new ProfilePathProcessorCursors(cursors.base, cursors.baseCursor, ndc, - cursors.contextName, cursors.resultPathBase)); - if (e == null) - throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.DID_NOT_FIND_SINGLE_SLICE_, diffMatches.get(0).getPath())); - e.setSlicing(diffMatches.get(0).getSlicing()); - slicerElement = e; - start++; - } else { - // we're just going to accept the differential slicing at face value - ElementDefinition outcome = profileUtilities.updateURLs(url, webUrl, currentBase.copy()); - outcome.setPath(profileUtilities.fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); - profileUtilities.updateFromBase(outcome, currentBase, srcSD.getUrl()); - - if (!diffMatches.get(0).hasSlicing()) - outcome.setSlicing(profileUtilities.makeExtensionSlicing()); - else - outcome.setSlicing(diffMatches.get(0).getSlicing().copy()); - if (!outcome.getPath().startsWith(cursors.resultPathBase)) - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH)); - result.getElement().add(outcome); - slicerElement = outcome; - - // differential - if the first one in the list has a name, we'll process it. Else we'll treat it as the base definition of the slice. - if (!diffMatches.get(0).hasSliceName()) { - profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), profileName, trimDifferential, url, srcSD, derived); - profileUtilities.removeStatusExtensions(outcome); - if (!outcome.hasContentReference() && !outcome.hasType()) { - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.NOT_DONE_YET)); - } - if (profileUtilities.hasInnerDiffMatches(differential, currentBasePath, cursors.diffCursor, diffLimit, cursors.base.getElement(), false)) { - if (profileUtilities.baseHasChildren(cursors.base, currentBase)) { // not a new type here - throw new Error("This situation is not yet handled (constrain slicing to 1..1 and fix base slice for inline structure - please report issue to grahame@fhir.org along with a test case that reproduces this error (@ " + currentBasePath + " | " + currentBase.getPath() + ")"); - } else { - StructureDefinition dt = profileUtilities.getTypeForElement(differential, cursors.diffCursor, profileName, diffMatches, outcome, webUrl, derived); - cursors.contextName = dt.getUrl(); - cursors.diffCursor++; - start = cursors.diffCursor; - while (differential.getElement().size() > cursors.diffCursor && profileUtilities.pathStartsWith(differential.getElement().get(cursors.diffCursor).getPath(), currentBasePath + ".")) - cursors.diffCursor++; - cursors.diffCursor--; - processPaths(indent + " ", result, differential, dt.getSnapshot().getElement().size() - 1, cursors.diffCursor, url, profileUtilities.getWebUrl(dt, webUrl, indent), profileName, currentBasePath, outcome.getPath(), trimDifferential, false, null, null, redirector, srcSD, /* starting again on the data type, but skip the root */ - derived, new ProfilePathProcessorCursors(dt.getSnapshot(), 1 /* starting again on the data type, but skip the root */, start, - cursors.contextName, cursors.resultPathBase)); - } - } - start++; - // result.getElement().remove(result.getElement().size()-1); - } else - profileUtilities.checkExtensionDoco(outcome); - } - // now, for each entry in the diff matches, we're going to process the base item - // our processing scope for base is all the children of the current path - int ndc = cursors.diffCursor; - int ndl = cursors.diffCursor; - for (int i = start; i < diffMatches.size(); i++) { - // our processing scope for the differential is the item in the list, and all the items before the next one in the list - ndc = differential.getElement().indexOf(diffMatches.get(i)); - ndl = profileUtilities.findEndOfElement(differential, ndc); -/* if (skipSlicingElement && i == 0) { - ndc = ndc + 1; - if (ndc > ndl) - continue; - }*/ - // now we process the base scope repeatedly for each instance of the item in the differential list - processPaths(indent + " ", result, differential, nbl, ndl, url, webUrl, profileName + profileUtilities.pathTail(diffMatches, i), contextPathSrc, contextPathDst, trimDifferential, true, slicerElement, null, redirector, srcSD, derived, new ProfilePathProcessorCursors(cursors.base, cursors.baseCursor, ndc, cursors.contextName, cursors.resultPathBase)); - } - // ok, done with that - next in the base list - cursors.baseCursor = nbl + 1; - cursors.diffCursor = ndl + 1; - } - - return res; - } - - private void processPathWithSlicedBase( - ElementDefinition currentBase, - String currentBasePath, - List diffMatches, List typeList, - final String indent, - final StructureDefinition.StructureDefinitionSnapshotComponent result, - final StructureDefinition.StructureDefinitionDifferentialComponent differential, final int baseLimit, final int diffLimit, final String url, final String webUrl, final String profileName, final String contextPathSrc, final String contextPathDst, final boolean trimDifferential, final boolean slicingDone, final ElementDefinition slicer, final String typeSlicingPath, final List redirector, final StructureDefinition srcSD, - StructureDefinition derived, ProfilePathProcessorCursors cursors - ) { - // the item is already sliced in the base profile. - // here's the rules - // 1. irrespective of whether the slicing is ordered or not, the definition order must be maintained - // 2. slice element names have to match. - // 3. new slices must be introduced at the end - // corallory: you can't re-slice existing slices. is that ok? - - // we're going to need this: - String path = currentBase.getPath(); - ElementDefinition original = currentBase; - - if (diffMatches.isEmpty()) { - if (profileUtilities.hasInnerDiffMatches(differential, path, cursors.diffCursor, diffLimit, cursors.base.getElement(), true)) { - // so we just copy it in - ElementDefinition outcome = profileUtilities.updateURLs(url, webUrl, currentBase.copy()); - outcome.setPath(profileUtilities.fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); - profileUtilities.updateFromBase(outcome, currentBase, srcSD.getUrl()); - profileUtilities.markDerived(outcome); - if (cursors.resultPathBase == null) - cursors.resultPathBase = outcome.getPath(); - else if (!outcome.getPath().startsWith(cursors.resultPathBase)) - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH)); - result.getElement().add(outcome); - // the profile walks into this, so we need to as well - // did we implicitly step into a new type? - if (profileUtilities.baseHasChildren(cursors.base, currentBase)) { // not a new type here - processPaths(indent + " ", result, differential, baseLimit, diffLimit, url, webUrl, profileName, contextPathSrc, contextPathDst, trimDifferential, false, null, null, redirector, srcSD, derived, new ProfilePathProcessorCursors(cursors.base, cursors.baseCursor + 1, cursors.diffCursor, cursors.contextName, cursors.resultPathBase)); - cursors.baseCursor = profileUtilities.indexOfFirstNonChild(cursors.base, currentBase, cursors.baseCursor, baseLimit); - } else { - StructureDefinition dt = profileUtilities.getTypeForElement(differential, cursors.diffCursor, profileName, diffMatches, outcome, webUrl, derived); - cursors.contextName = dt.getUrl(); - int start = cursors.diffCursor; - if (differential.getElement().get(cursors.diffCursor).getPath().equals(currentBasePath)) { - cursors.diffCursor++; - } - while (differential.getElement().size() > cursors.diffCursor && profileUtilities.pathStartsWith(differential.getElement().get(cursors.diffCursor).getPath(), currentBasePath + ".")) { - cursors.diffCursor++; - } - if (cursors.diffCursor > start) { - processPaths(indent + " ", result, differential, dt.getSnapshot().getElement().size() - 1, cursors.diffCursor - 1, url, profileUtilities.getWebUrl(dt, webUrl, indent), profileName, currentBasePath, outcome.getPath(), trimDifferential, false, null, null, redirector, srcSD, /* starting again on the data type, but skip the root */ - derived, new ProfilePathProcessorCursors(dt.getSnapshot(), 1 /* starting again on the data type, but skip the root */, start, - cursors.contextName, cursors.resultPathBase)); - } - } - cursors.baseCursor++; - } else { - // the differential doesn't say anything about this item - // copy across the currentbase, and all of its children and siblings - while (cursors.baseCursor < cursors.base.getElement().size() && cursors.base.getElement().get(cursors.baseCursor).getPath().startsWith(path)) { - ElementDefinition outcome = profileUtilities.updateURLs(url, webUrl, cursors.base.getElement().get(cursors.baseCursor).copy()); - outcome.setPath(profileUtilities.fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); - if (!outcome.getPath().startsWith(cursors.resultPathBase)) - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH_IN_PROFILE___VS_, profileName, outcome.getPath(), cursors.resultPathBase)); - result.getElement().add(outcome); // so we just copy it in - outcome.setUserData(profileUtilities.BASE_MODEL, srcSD.getUrl()); - outcome.setUserData(profileUtilities.BASE_PATH, cursors.resultPathBase); - cursors.baseCursor++; - } - } - } else if (profileUtilities.diffsConstrainTypes(diffMatches, currentBasePath, typeList)) { - int start = 0; - int nbl = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor); - int ndc = differential.getElement().indexOf(diffMatches.get(0)); - ElementDefinition elementToRemove = null; - boolean shortCut = (!typeList.isEmpty() && typeList.get(0).type != null) || (diffMatches.get(0).hasSliceName() && !diffMatches.get(0).hasSlicing()); - // we come here whether they are sliced in the diff, or whether the short cut is used. - if (shortCut) { - // this is the short cut method, we've just dived in and specified a type slice. - // in R3 (and unpatched R4, as a workaround right now... - if (!VersionUtilities.isR4Plus(profileUtilities.getContext().getVersion()) || !profileUtilities.isNewSlicingProcessing()) { // newSlicingProcessing is a work around for editorial loop dependency - // we insert a cloned element with the right types at the start of the diffMatches - ElementDefinition ed = new ElementDefinition(); - ed.setPath(profileUtilities.determineTypeSlicePath(diffMatches.get(0).getPath(), currentBasePath)); - for (TypeSlice ts : typeList) - ed.addType().setCode(ts.type); - ed.setSlicing(new ElementDefinition.ElementDefinitionSlicingComponent()); - ed.getSlicing().addDiscriminator().setType(ElementDefinition.DiscriminatorType.TYPE).setPath("$this"); - ed.getSlicing().setRules(ElementDefinition.SlicingRules.CLOSED); - ed.getSlicing().setOrdered(false); - diffMatches.add(0, ed); - differential.getElement().add(ndc, ed); - elementToRemove = ed; - } else { - // as of R4, this changed; if there's no slice, there's no constraint on the slice types, only one the type. - // so the element we insert specifies no types (= all types) allowed in the base, not just the listed type. - // see also discussion here: https://chat.fhir.org/#narrow/stream/179177-conformance/topic/Slicing.20a.20non-repeating.20element - ElementDefinition ed = new ElementDefinition(); - ed.setPath(profileUtilities.determineTypeSlicePath(diffMatches.get(0).getPath(), currentBasePath)); - ed.setSlicing(new ElementDefinition.ElementDefinitionSlicingComponent()); - ed.getSlicing().addDiscriminator().setType(ElementDefinition.DiscriminatorType.TYPE).setPath("$this"); - ed.getSlicing().setRules(ElementDefinition.SlicingRules.CLOSED); - ed.getSlicing().setOrdered(false); - diffMatches.add(0, ed); - differential.getElement().add(ndc, ed); - elementToRemove = ed; - } - } - int ndl = profileUtilities.findEndOfElement(differential, ndc); - // the first element is setting up the slicing - - if (diffMatches.get(0).getSlicing().hasOrdered()) { - if (diffMatches.get(0).getSlicing().getOrdered()) { - throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGORDERED__TRUE, currentBasePath, url)); - } - } - if (diffMatches.get(0).getSlicing().hasDiscriminator()) { - if (diffMatches.get(0).getSlicing().getDiscriminator().size() != 1) { - throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORCOUNT__1, currentBasePath, url)); - } - if (diffMatches.get(0).getSlicing().getDiscriminatorFirstRep().getType() != ElementDefinition.DiscriminatorType.TYPE) { - throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORTYPE__TYPE, currentBasePath, url)); - } - if (!"$this".equals(diffMatches.get(0).getSlicing().getDiscriminatorFirstRep().getPath())) { - throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORPATH__THIS, currentBasePath, url)); - } - } - // check the slice names too while we're at it... - for (TypeSlice ts : typeList) { - if (ts.type != null) { - String tn = profileUtilities.rootName(currentBasePath) + Utilities.capitalize(ts.type); - if (!ts.defn.hasSliceName()) { - ts.defn.setSliceName(tn); - } else if (!ts.defn.getSliceName().equals(tn)) { - throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_NAME_MUST_BE__BUT_IS_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : currentBasePath), tn, ts.defn.getSliceName())); - } - if (!ts.defn.hasType()) { - ts.defn.addType().setCode(ts.type); - } else if (ts.defn.getType().size() > 1) { - throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_MORE_THAN_ONE_TYPE_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : currentBasePath), tn, ts.defn.typeSummary())); - } else if (!ts.defn.getType().get(0).getCode().equals(ts.type)) { - throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_WRONG_TYPE_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : currentBasePath), tn, ts.defn.typeSummary())); - } - } - } - - // ok passed the checks. - // copy the root diff, and then process any children it has - ElementDefinition e = processPaths(indent + " ", result, differential, nbl, ndl, url, webUrl, profileName + profileUtilities.pathTail(diffMatches, 0), contextPathSrc, contextPathDst, trimDifferential, true, null, currentBasePath, redirector, srcSD, - derived, new ProfilePathProcessorCursors(cursors.base, cursors.baseCursor, ndc, - cursors.contextName, cursors.resultPathBase)); - if (e == null) - throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.DID_NOT_FIND_TYPE_ROOT_, diffMatches.get(0).getPath())); - // now set up slicing on the e (cause it was wiped by what we called. - e.setSlicing(new ElementDefinition.ElementDefinitionSlicingComponent()); - e.getSlicing().addDiscriminator().setType(ElementDefinition.DiscriminatorType.TYPE).setPath("$this"); - e.getSlicing().setRules(ElementDefinition.SlicingRules.CLOSED); // type slicing is always closed; the differential might call it open, but that just means it's not constraining the slices it doesn't mention - e.getSlicing().setOrdered(false); - start++; - - String fixedType = null; - List baseSlices = profileUtilities.findBaseSlices(cursors.base, nbl); - // now process the siblings, which should each be type constrained - and may also have their own children. they may match existing slices - // now we process the base scope repeatedly for each instance of the item in the differential list - for (int i = start; i < diffMatches.size(); i++) { - String type = profileUtilities.determineFixedType(diffMatches, fixedType, i); - // our processing scope for the differential is the item in the list, and all the items before the next one in the list - if (diffMatches.get(i).getMin() > 0) { - if (diffMatches.size() > i + 1) { - throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.INVALID_SLICING__THERE_IS_MORE_THAN_ONE_TYPE_SLICE_AT__BUT_ONE_OF_THEM__HAS_MIN__1_SO_THE_OTHER_SLICES_CANNOT_EXIST, diffMatches.get(i).getPath(), diffMatches.get(i).getSliceName())); - } - fixedType = type; - } - ndc = differential.getElement().indexOf(diffMatches.get(i)); - ndl = profileUtilities.findEndOfElement(differential, ndc); - int sStart = cursors.baseCursor; - int sEnd = nbl; - BaseTypeSlice bs = profileUtilities.chooseMatchingBaseSlice(baseSlices, type); - if (bs != null) { - sStart = bs.getStart(); - sEnd = bs.getEnd(); - bs.setHandled(true); - } - processPaths(indent + " ", result, differential, sEnd, ndl, url, webUrl, profileName + profileUtilities.pathTail(diffMatches, i), contextPathSrc, contextPathDst, trimDifferential, true, e, currentBasePath, redirector, srcSD, derived, new ProfilePathProcessorCursors(cursors.base, sStart, ndc, cursors.contextName, cursors.resultPathBase)); - } - if (elementToRemove != null) { - differential.getElement().remove(elementToRemove); - ndl--; - } - if (fixedType != null) { - for (Iterator iter = e.getType().iterator(); iter.hasNext(); ) { - ElementDefinition.TypeRefComponent tr = iter.next(); - if (!tr.getCode().equals(fixedType)) { - iter.remove(); - } - } - } - for (BaseTypeSlice bs : baseSlices) { - if (!bs.isHandled()) { - // ok we gimme up a fake differential that says nothing, and run that against the slice. - StructureDefinition.StructureDefinitionDifferentialComponent fakeDiff = new StructureDefinition.StructureDefinitionDifferentialComponent(); - fakeDiff.getElementFirstRep().setPath(bs.getDefn().getPath()); - processPaths(indent + " ", result, fakeDiff, bs.getEnd(), 0, url, webUrl, profileName + profileUtilities.tail(bs.getDefn().getPath()), contextPathSrc, contextPathDst, trimDifferential, true, e, currentBasePath, redirector, srcSD, derived, new ProfilePathProcessorCursors(cursors.base, bs.getStart(), 0, cursors.contextName, cursors.resultPathBase)); - - } - } - // ok, done with that - next in the base list - cursors.baseCursor = baseSlices.get(baseSlices.size() - 1).getEnd() + 1; - cursors.diffCursor = ndl + 1; - //throw new Error("not done yet - slicing / types @ "+cpath); - } else { - // first - check that the slicing is ok - boolean closed = currentBase.getSlicing().getRules() == ElementDefinition.SlicingRules.CLOSED; - int diffpos = 0; - boolean isExtension = currentBasePath.endsWith(".extension") || currentBasePath.endsWith(".modifierExtension"); - if (diffMatches.get(0).hasSlicing()) { // it might be null if the differential doesn't want to say anything about slicing -// if (!isExtension) -// diffpos++; // if there's a slice on the first, we'll ignore any content it has - ElementDefinition.ElementDefinitionSlicingComponent dSlice = diffMatches.get(0).getSlicing(); - ElementDefinition.ElementDefinitionSlicingComponent bSlice = currentBase.getSlicing(); - if (dSlice.hasOrderedElement() && bSlice.hasOrderedElement() && !profileUtilities.orderMatches(dSlice.getOrderedElement(), bSlice.getOrderedElement())) - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.SLICING_RULES_ON_DIFFERENTIAL__DO_NOT_MATCH_THOSE_ON_BASE___ORDER___, profileUtilities.summarizeSlicing(dSlice), profileUtilities.summarizeSlicing(bSlice), path, cursors.contextName)); - if (!profileUtilities.discriminatorMatches(dSlice.getDiscriminator(), bSlice.getDiscriminator())) - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.SLICING_RULES_ON_DIFFERENTIAL__DO_NOT_MATCH_THOSE_ON_BASE___DISCIMINATOR___, profileUtilities.summarizeSlicing(dSlice), profileUtilities.summarizeSlicing(bSlice), path, cursors.contextName)); - if (!currentBase.isChoice() && !profileUtilities.ruleMatches(dSlice.getRules(), bSlice.getRules())) - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.SLICING_RULES_ON_DIFFERENTIAL__DO_NOT_MATCH_THOSE_ON_BASE___RULE___, profileUtilities.summarizeSlicing(dSlice), profileUtilities.summarizeSlicing(bSlice), path, cursors.contextName)); - } - ElementDefinition outcome = profileUtilities.updateURLs(url, webUrl, currentBase.copy()); - outcome.setPath(profileUtilities.fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); - profileUtilities.updateFromBase(outcome, currentBase, srcSD.getUrl()); - if (diffMatches.get(0).hasSlicing() || !diffMatches.get(0).hasSliceName()) { - profileUtilities.updateFromSlicing(outcome.getSlicing(), diffMatches.get(0).getSlicing()); - profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), profileName, closed, url, srcSD, derived); // if there's no slice, we don't want to update the unsliced description - profileUtilities.removeStatusExtensions(outcome); - } else if (!diffMatches.get(0).hasSliceName()) { - diffMatches.get(0).setUserData(profileUtilities.GENERATED_IN_SNAPSHOT, outcome); // because of updateFromDefinition isn't called - } - - result.getElement().add(outcome); - - if (!diffMatches.get(0).hasSliceName()) { // it's not real content, just the slice - diffpos++; - } - if (profileUtilities.hasInnerDiffMatches(differential, currentBasePath, cursors.diffCursor, diffLimit, cursors.base.getElement(), false)) { - int nbl = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor); - int ndx = differential.getElement().indexOf(diffMatches.get(0)); - int ndc = ndx + (diffMatches.get(0).hasSlicing() ? 1 : 0); - int ndl = profileUtilities.findEndOfElement(differential, ndx); - if (nbl == cursors.baseCursor) { - if (cursors.base.getElement().get(cursors.baseCursor).getType().size() != 1) { - throw new Error(profileUtilities.getContext().formatMessage(I18nConstants.DIFFERENTIAL_WALKS_INTO____BUT_THE_BASE_DOES_NOT_AND_THERE_IS_NOT_A_SINGLE_FIXED_TYPE_THE_TYPE_IS__THIS_IS_NOT_HANDLED_YET, currentBasePath, diffMatches.get(0).toString(), cursors.base.getElement().get(cursors.baseCursor).typeSummary())); - } - StructureDefinition dt = profileUtilities.getProfileForDataType(cursors.base.getElement().get(cursors.baseCursor).getType().get(0), webUrl, derived); - if (dt == null) { - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.UNKNOWN_TYPE__AT_, outcome.getType().get(0), diffMatches.get(0).getPath())); - } - cursors.contextName = dt.getUrl(); - while (differential.getElement().size() > cursors.diffCursor && profileUtilities.pathStartsWith(differential.getElement().get(cursors.diffCursor).getPath(), currentBasePath + ".")) - cursors.diffCursor++; - processPaths(indent + " ", result, differential, dt.getSnapshot().getElement().size() - 1, ndl, url, profileUtilities.getWebUrl(dt, webUrl, indent), profileName, currentBasePath, outcome.getPath(), trimDifferential, false, null, null, redirector, srcSD, - derived, new ProfilePathProcessorCursors(dt.getSnapshot(), 1, ndc, - cursors.contextName, cursors.resultPathBase)); - } else { - processPaths(indent + " ", result, differential, nbl, ndl, url, webUrl, profileName + profileUtilities.pathTail(diffMatches, 0), contextPathSrc, contextPathDst, trimDifferential, false, null, null, null, srcSD, - derived, new ProfilePathProcessorCursors(cursors.base, cursors.baseCursor + 1, ndc, - cursors.contextName, cursors.resultPathBase)); - } -// throw new Error("Not done yet"); -// } else if (currentBase.getType().get(0).getCode().equals("BackboneElement") && diffMatches.size() > 0 && diffMatches.get(0).hasSliceName()) { - } else if (currentBase.getType().get(0).getCode().equals("BackboneElement")) { - // We need to copy children of the backbone element before we start messing around with slices - int nbl = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor); - for (int i = cursors.baseCursor + 1; i <= nbl; i++) { - outcome = profileUtilities.updateURLs(url, webUrl, cursors.base.getElement().get(i).copy()); - result.getElement().add(outcome); - } - } - - // now, we have two lists, base and diff. we're going to work through base, looking for matches in diff. - List baseMatches = profileUtilities.getSiblings(cursors.base.getElement(), currentBase); - for (ElementDefinition baseItem : baseMatches) { - cursors.baseCursor = cursors.base.getElement().indexOf(baseItem); - outcome = profileUtilities.updateURLs(url, webUrl, baseItem.copy()); - profileUtilities.updateFromBase(outcome, currentBase, srcSD.getUrl()); - outcome.setPath(profileUtilities.fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); - outcome.setSlicing(null); - if (!outcome.getPath().startsWith(cursors.resultPathBase)) - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH)); - if (diffpos < diffMatches.size() && diffMatches.get(diffpos).hasSliceName() && diffMatches.get(diffpos).getSliceName().equals(outcome.getSliceName())) { - // if there's a diff, we update the outcome with diff - // no? updateFromDefinition(outcome, diffMatches.get(diffpos), profileName, closed, url); - //then process any children - int nbl = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor); - int ndc = differential.getElement().indexOf(diffMatches.get(diffpos)); - int ndl = profileUtilities.findEndOfElement(differential, ndc); - // now we process the base scope repeatedly for each instance of the item in the differential list - processPaths(indent + " ", result, differential, nbl, ndl, url, webUrl, profileName + profileUtilities.pathTail(diffMatches, diffpos), contextPathSrc, contextPathDst, closed, true, null, null, redirector, srcSD, derived, new ProfilePathProcessorCursors(cursors.base, cursors.baseCursor, ndc, cursors.contextName, cursors.resultPathBase)); - // ok, done with that - now set the cursors for if this is the end - cursors.baseCursor = nbl; - cursors.diffCursor = ndl + 1; - diffpos++; - } else { - result.getElement().add(outcome); - cursors.baseCursor++; - // just copy any children on the base - while (cursors.baseCursor < cursors.base.getElement().size() && cursors.base.getElement().get(cursors.baseCursor).getPath().startsWith(path) && !cursors.base.getElement().get(cursors.baseCursor).getPath().equals(path)) { - outcome = profileUtilities.updateURLs(url, webUrl, cursors.base.getElement().get(cursors.baseCursor).copy()); - outcome.setPath(profileUtilities.fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); - if (!outcome.getPath().startsWith(cursors.resultPathBase)) - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH)); - outcome.setUserData(profileUtilities.BASE_PATH, outcome.getPath()); - outcome.setUserData(profileUtilities.BASE_MODEL, srcSD.getUrl()); - result.getElement().add(outcome); - cursors.baseCursor++; - } - //Lloyd - add this for test T15 - cursors.baseCursor--; - } - } - // finally, we process any remaining entries in diff, which are new (and which are only allowed if the base wasn't closed - boolean checkImplicitTypes = false; - if (closed && diffpos < diffMatches.size()) { - // this is a problem, unless we're on a polymorhpic type and we're going to constrain a slice that actually implicitly exists - if (currentBase.getPath().endsWith("[x]")) { - checkImplicitTypes = true; - } else { - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.THE_BASE_SNAPSHOT_MARKS_A_SLICING_AS_CLOSED_BUT_THE_DIFFERENTIAL_TRIES_TO_EXTEND_IT_IN__AT__, profileName, path, currentBasePath)); - } - } - if (diffpos == diffMatches.size()) { -//Lloyd This was causing problems w/ Telus -// diffCursor++; - } else { - while (diffpos < diffMatches.size()) { - ElementDefinition diffItem = diffMatches.get(diffpos); - for (ElementDefinition baseItem : baseMatches) - if (baseItem.getSliceName().equals(diffItem.getSliceName())) - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.NAMED_ITEMS_ARE_OUT_OF_ORDER_IN_THE_SLICE)); - outcome = profileUtilities.updateURLs(url, webUrl, currentBase.copy()); - // outcome = updateURLs(url, diffItem.copy()); - outcome.setPath(profileUtilities.fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); - profileUtilities.updateFromBase(outcome, currentBase, srcSD.getUrl()); - outcome.setSlicing(null); - outcome.setMin(0); // we're in a slice, so it's only a mandatory if it's explicitly marked so - if (!outcome.getPath().startsWith(cursors.resultPathBase)) - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH)); - result.getElement().add(outcome); - profileUtilities.updateFromDefinition(outcome, diffItem, profileName, trimDifferential, url, srcSD, derived); - profileUtilities.removeStatusExtensions(outcome); - // --- LM Added this - cursors.diffCursor = differential.getElement().indexOf(diffItem) + 1; - if (!outcome.getType().isEmpty() && (/*outcome.getType().get(0).getCode().equals("Extension") || */differential.getElement().size() > cursors.diffCursor) && outcome.getPath().contains(".")/* && isDataType(outcome.getType())*/) { // don't want to do this for the root, since that's base, and we're already processing it - if (!profileUtilities.baseWalksInto(cursors.base.getElement(), cursors.baseCursor)) { - if (differential.getElement().size() > cursors.diffCursor && profileUtilities.pathStartsWith(differential.getElement().get(cursors.diffCursor).getPath(), diffMatches.get(0).getPath() + ".")) { - if (outcome.getType().size() > 1) - for (ElementDefinition.TypeRefComponent t : outcome.getType()) { - if (!t.getCode().equals("Reference")) - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants._HAS_CHILDREN__AND_MULTIPLE_TYPES__IN_PROFILE_, diffMatches.get(0).getPath(), differential.getElement().get(cursors.diffCursor).getPath(), profileUtilities.typeCode(outcome.getType()), profileName)); - } - ElementDefinition.TypeRefComponent t = outcome.getType().get(0); - if (t.getCode().equals("BackboneElement")) { - int baseStart = cursors.base.getElement().indexOf(currentBase) + 1; - int baseMax = baseStart + 1; - while (baseMax < cursors.base.getElement().size() && cursors.base.getElement().get(baseMax).getPath().startsWith(currentBase.getPath() + ".")) - baseMax++; - int start = cursors.diffCursor; - while (differential.getElement().size() > cursors.diffCursor && profileUtilities.pathStartsWith(differential.getElement().get(cursors.diffCursor).getPath(), diffMatches.get(0).getPath() + ".")) - cursors.diffCursor++; - processPaths(indent + " ", result, differential, baseMax - 1, cursors.diffCursor - 1, url, webUrl, profileName + profileUtilities.pathTail(diffMatches, 0), cursors.base.getElement().get(0).getPath(), cursors.base.getElement().get(0).getPath(), trimDifferential, false, null, null, redirector, srcSD, - derived, new ProfilePathProcessorCursors(cursors.base, baseStart, start - 1, - cursors.contextName, cursors.resultPathBase)); - - } else { - StructureDefinition dt = profileUtilities.getProfileForDataType(outcome.getType().get(0), webUrl, derived); - // if (t.getCode().equals("Extension") && t.hasProfile() && !t.getProfile().contains(":")) { - // lloydfix dt = - // } - if (dt == null) - throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants._HAS_CHILDREN__FOR_TYPE__IN_PROFILE__BUT_CANT_FIND_TYPE, diffMatches.get(0).getPath(), differential.getElement().get(cursors.diffCursor).getPath(), profileUtilities.typeCode(outcome.getType()), profileName)); - cursors.contextName = dt.getUrl(); - int start = cursors.diffCursor; - while (differential.getElement().size() > cursors.diffCursor && profileUtilities.pathStartsWith(differential.getElement().get(cursors.diffCursor).getPath(), diffMatches.get(0).getPath() + ".")) - cursors.diffCursor++; - processPaths(indent + " ", result, differential, dt.getSnapshot().getElement().size() - 1, cursors.diffCursor - 1, url, profileUtilities.getWebUrl(dt, webUrl, indent), profileName + profileUtilities.pathTail(diffMatches, 0), diffMatches.get(0).getPath(), outcome.getPath(), trimDifferential, false, null, null, redirector, srcSD, /* starting again on the data type, but skip the root */ - derived, new ProfilePathProcessorCursors(dt.getSnapshot(), 1 /* starting again on the data type, but skip the root */, start - 1, - cursors.contextName, cursors.resultPathBase)); - } - } - } - } - // --- - diffpos++; - } - } - cursors.baseCursor++; - } - } - private boolean oneMatchingElementInDifferential(boolean slicingDone, String path, List diffMatches) { - if (diffMatches.size() != 1) { - return false; - } - if (slicingDone) { - return true; - } - if (profileUtilities.isImplicitSlicing(diffMatches.get(0), path)) { - return false; - } - return !(diffMatches.get(0).hasSlicing() - || (profileUtilities.isExtension(diffMatches.get(0)) - && diffMatches.get(0).hasSliceName())); - } - - -} diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ShExGenerator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ShExGenerator.java index 07009a442..d119aaa97 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ShExGenerator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ShExGenerator.java @@ -1,33 +1,33 @@ package org.hl7.fhir.r5.conformance; -/* - 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. - - */ +/* + 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. + + */ @@ -42,6 +42,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.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.model.Constants; import org.hl7.fhir.r5.model.DataType; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/XmlSchemaGenerator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/XmlSchemaGenerator.java index 98d65de64..bef045cb9 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/XmlSchemaGenerator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/XmlSchemaGenerator.java @@ -1,33 +1,33 @@ package org.hl7.fhir.r5.conformance; -/* - 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. - - */ +/* + 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.FileOutputStream; @@ -71,6 +71,7 @@ import java.util.Queue; import java.util.Set; import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.ElementDefinition.PropertyRepresentation; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/BaseTypeSlice.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/BaseTypeSlice.java similarity index 94% rename from org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/BaseTypeSlice.java rename to org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/BaseTypeSlice.java index 8e512d7d4..9cc80be23 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/BaseTypeSlice.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/BaseTypeSlice.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.r5.conformance; +package org.hl7.fhir.r5.conformance.profile; import org.hl7.fhir.r5.model.ElementDefinition; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/PathSlicingParams.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/PathSlicingParams.java new file mode 100644 index 000000000..7563e18c8 --- /dev/null +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/PathSlicingParams.java @@ -0,0 +1,22 @@ +package org.hl7.fhir.r5.conformance.profile; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.hl7.fhir.r5.model.ElementDefinition; + +@AllArgsConstructor(access = AccessLevel.PROTECTED) +public class PathSlicingParams { + @Getter + final boolean done; + @Getter + final ElementDefinition elementDefinition; + @Getter + final String path; + + public PathSlicingParams() { + done = false; + elementDefinition = null; + path = null; + } +} diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessor.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessor.java new file mode 100644 index 000000000..60559e0ee --- /dev/null +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessor.java @@ -0,0 +1,1290 @@ +package org.hl7.fhir.r5.conformance.profile; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.With; +import org.hl7.fhir.exceptions.DefinitionException; +import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.r5.conformance.ElementRedirection; +import org.hl7.fhir.r5.model.CanonicalType; +import org.hl7.fhir.r5.model.ElementDefinition; +import org.hl7.fhir.r5.model.StructureDefinition; +import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.VersionUtilities; +import org.hl7.fhir.utilities.i18n.I18nConstants; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class ProfilePathProcessor { + + @Getter + protected final ProfileUtilities profileUtilities; + + @Getter + @With + final String debugIndent; + + @Getter + @With + final StructureDefinition.StructureDefinitionSnapshotComponent result; + + @Getter + @With + final StructureDefinition.StructureDefinitionDifferentialComponent differential; + + @Getter + @With + final int baseLimit; + + @Getter + @With + final int diffLimit; + + @Getter + @With + final String url; + + @Getter + @With + final String webUrl; + + @Getter + @With + final String profileName; + + @Getter + @With + final String contextPathSource; + + @Getter + @With + final String contextPathTarget; + + @Getter + @With + final boolean trimDifferential; + + @Getter + @With + final List redirector; + + @Getter + @With + final StructureDefinition sourceStructureDefinition; + + @Getter + @With + final StructureDefinition derived; + + @Getter + @With + final PathSlicingParams slicing; + + private ProfilePathProcessor( + ProfileUtilities profileUtilities + ) { + this.profileUtilities = profileUtilities; + debugIndent = ""; + this.result = null; + this.differential = null; + this.baseLimit = 0; + this.diffLimit = 0; + this.url = null; + this.webUrl = null; + this.profileName = null; + this.contextPathSource = null; + this.contextPathTarget = null; + this.trimDifferential = false; + this.redirector = null; + this.sourceStructureDefinition = null; + this.derived = null; + this.slicing = null; + } + + public static ProfilePathProcessor getInstance( ProfileUtilities profileUtilities) { + return new ProfilePathProcessor(profileUtilities); + } + + public ProfilePathProcessor incrementDebugIndent() { + return this.withDebugIndent(this.debugIndent + " ".repeat(2)); + } + + + protected static void processPaths(ProfileUtilities profileUtilities, StructureDefinition base, StructureDefinition derived, String url, String webUrl, StructureDefinition.StructureDefinitionDifferentialComponent differential, StructureDefinition.StructureDefinitionSnapshotComponent baseSnapshot) { + + ProfilePathProcessorState cursors = new ProfilePathProcessorState( + baseSnapshot, + 0, + 0, + base.getUrl(), + null); + + + getInstance(profileUtilities) + .withResult(derived.getSnapshot()) + .withDifferential(differential) + .withBaseLimit(baseSnapshot.getElement().size() - 1) + .withDiffLimit(derived.getDifferential().hasElement() ? derived.getDifferential().getElement().size() - 1 : -1) + .withUrl(url) + .withWebUrl(webUrl) + .withProfileName(derived.present()) + .withContextPathSource(null) + .withContextPathTarget(null) + .withTrimDifferential(false) + .withRedirector(new ArrayList()) + .withSourceStructureDefinition(base) + .withDerived(derived) + .withSlicing(new PathSlicingParams()).processPaths(cursors); + + } + + /** + * @param cursors + * @throws DefinitionException, FHIRException + * @throws Exception + */ + private ElementDefinition processPaths( + final ProfilePathProcessorState cursors) throws FHIRException { + debugProcessPathsEntry(cursors); + ElementDefinition res = null; + List typeList = new ArrayList<>(); + // just repeat processing entries until we run out of our allowed scope (1st entry, the allowed scope is all the entries) + while (cursors.baseCursor <= getBaseLimit()) { + // get the current focus of the base, and decide what to do + ElementDefinition currentBase = cursors.base.getElement().get(cursors.baseCursor); + String currentBasePath = profileUtilities.fixedPathSource(getContextPathSource(), currentBase.getPath(), getRedirector()); + debugProcessPathsIteration(cursors, currentBasePath); + List diffMatches = profileUtilities.getDiffMatches(getDifferential(), currentBasePath, cursors.diffCursor, getDiffLimit(), getProfileName()); // get a list of matching elements in scope + + // in the simple case, source is not sliced. + if (!currentBase.hasSlicing() || currentBasePath.equals(getSlicing().getPath())) + { + ElementDefinition currentRes = processSimplePath(currentBase, currentBasePath, diffMatches, typeList, + cursors + ); + if (res == null) { + res = currentRes; + } + } + else { + processPathWithSlicedBase(currentBase, currentBasePath, diffMatches, typeList, + cursors + ); + } + } + + int i = 0; + for (ElementDefinition e : getResult().getElement()) { + i++; + if (e.hasMinElement() && e.getMinElement().getValue() == null) + throw new Error(profileUtilities.getContext().formatMessage(I18nConstants.NULL_MIN)); + } + return res; + } + + private void debugProcessPathsIteration(ProfilePathProcessorState cursors, String currentBasePath) { + if (profileUtilities.isDebug()) { + System.out.println(getDebugIndent() + " - " + currentBasePath + ": base = " + cursors.baseCursor + " (" + profileUtilities.descED(cursors.base.getElement(), cursors.baseCursor) + ") to " + getBaseLimit() + " (" + profileUtilities.descED(cursors.base.getElement(), getBaseLimit()) + "), diff = " + cursors.diffCursor + " (" + profileUtilities.descED(getDifferential().getElement(), cursors.diffCursor) + ") to " + getDiffLimit() + " (" + profileUtilities.descED(getDifferential().getElement(), getDiffLimit()) + ") " + + "(slicingDone = " + getSlicing().isDone() + ") (diffpath= " + (getDifferential().getElement().size() > cursors.diffCursor ? getDifferential().getElement().get(cursors.diffCursor).getPath() : "n/a") + ")"); + } + } + + private void debugProcessPathsEntry(ProfilePathProcessorState cursors) { + if (profileUtilities.isDebug()) { + System.out.println(getDebugIndent() + "PP @ " + cursors.resultPathBase + " / " + getContextPathSource() + " : base = " + cursors.baseCursor + " to " + getBaseLimit() + ", diff = " + cursors.diffCursor + " to " + getDiffLimit() + " (slicing = " + getSlicing().isDone() + ", k " + (getRedirector() == null ? "null" : getRedirector().toString()) + ")"); + } + } + + + public ElementDefinition processSimplePath( + final ElementDefinition currentBase, + final String currentBasePath, + final List diffMatches, + final List typeList, + final ProfilePathProcessorState cursors) throws FHIRException { + ElementDefinition res = null; + + // the differential doesn't say anything about this item + // so we just copy it in + if (diffMatches.isEmpty()) + processSimplePathWithEmptyDiffMatches(currentBase, currentBasePath, diffMatches, cursors); + // one matching element in the differential + else if (oneMatchingElementInDifferential(getSlicing().isDone(), currentBasePath, diffMatches)) + res = processSimplePathWithOneMatchingElementInDifferential(currentBase, currentBasePath, diffMatches, cursors); + else if (profileUtilities.diffsConstrainTypes(diffMatches, currentBasePath, typeList)) + processSimplePathWhereDiffsConstrainTypes(currentBasePath, diffMatches, typeList, cursors); + else + processSimplePathDefault(currentBase, currentBasePath, diffMatches, cursors); + + + return res; + } + + private void processSimplePathDefault(ElementDefinition currentBase, String currentBasePath, List diffMatches, ProfilePathProcessorState cursors) { + // ok, the differential slices the item. Let's check our pre-conditions to ensure that this is correct + if (!profileUtilities.unbounded(currentBase) && !profileUtilities.isSlicedToOneOnly(diffMatches.get(0))) + // you can only slice an element that doesn't repeat if the sum total of your slices is limited to 1 + // (but you might do that in order to split up constraints by type) + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ATTEMPT_TO_A_SLICE_AN_ELEMENT_THAT_DOES_NOT_REPEAT__FROM__IN_, currentBase.getPath(), currentBase.getPath(), cursors.contextName, diffMatches.get(0).getId(), profileUtilities.sliceNames(diffMatches))); + if (!diffMatches.get(0).hasSlicing() && !profileUtilities.isExtension(currentBase)) // well, the diff has set up a slice, but hasn't defined it. this is an error + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.DIFFERENTIAL_DOES_NOT_HAVE_A_SLICE__B_OF_____IN_PROFILE_, currentBase.getPath(), cursors.baseCursor, getBaseLimit(), cursors.diffCursor, getDiffLimit(), getUrl(), currentBasePath)); + + // well, if it passed those preconditions then we slice the dest. + int start = 0; + int newBaseLimit = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor); +// if (diffMatches.size() > 1 && diffMatches.get(0).hasSlicing() && differential.getElement().indexOf(diffMatches.get(1)) > differential.getElement().indexOf(diffMatches.get(0))+1) { + ElementDefinition slicerElement; + if (diffMatches.size() > 1 && diffMatches.get(0).hasSlicing() && (newBaseLimit > cursors.baseCursor || getDifferential().getElement().indexOf(diffMatches.get(1)) > getDifferential().getElement().indexOf(diffMatches.get(0)) + 1)) { // there's a default set before the slices + int newDiffCursor = getDifferential().getElement().indexOf(diffMatches.get(0)); + int newDiffLimit = profileUtilities.findEndOfElement(getDifferential(), newDiffCursor); + ElementDefinition e = + this + .incrementDebugIndent() + .withBaseLimit(newBaseLimit) + .withDiffLimit(newDiffLimit) + .withProfileName(getProfileName() + profileUtilities.pathTail(diffMatches, 0)).withSlicing(new PathSlicingParams(true, null, null)). + processPaths(new ProfilePathProcessorState(cursors.base, cursors.baseCursor, newDiffCursor, + cursors.contextName, cursors.resultPathBase)); + if (e == null) + throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.DID_NOT_FIND_SINGLE_SLICE_, diffMatches.get(0).getPath())); + e.setSlicing(diffMatches.get(0).getSlicing()); + slicerElement = e; + start++; + } else { + // we're just going to accept the differential slicing at face value + ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy()); + outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource())); + profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl()); + + if (!diffMatches.get(0).hasSlicing()) + outcome.setSlicing(profileUtilities.makeExtensionSlicing()); + else + outcome.setSlicing(diffMatches.get(0).getSlicing().copy()); + if (!outcome.getPath().startsWith(cursors.resultPathBase)) + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH)); + getResult().getElement().add(outcome); + slicerElement = outcome; + + // differential - if the first one in the list has a name, we'll process it. Else we'll treat it as the base definition of the slice. + if (!diffMatches.get(0).hasSliceName()) { + profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), getProfileName(), isTrimDifferential(), getUrl(),getSourceStructureDefinition(), getDerived()); + profileUtilities.removeStatusExtensions(outcome); + if (!outcome.hasContentReference() && !outcome.hasType()) { + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.NOT_DONE_YET)); + } + if (profileUtilities.hasInnerDiffMatches(getDifferential(), currentBasePath, cursors.diffCursor, getDiffLimit(), cursors.base.getElement(), false)) { + if (profileUtilities.baseHasChildren(cursors.base, currentBase)) { // not a new type here + throw new Error("This situation is not yet handled (constrain slicing to 1..1 and fix base slice for inline structure - please report issue to grahame@fhir.org along with a test case that reproduces this error (@ " + currentBasePath + " | " + currentBase.getPath() + ")"); + } else { + StructureDefinition dt = profileUtilities.getTypeForElement(getDifferential(), cursors.diffCursor, getProfileName(), diffMatches, outcome, getWebUrl(), getDerived()); + cursors.contextName = dt.getUrl(); + cursors.diffCursor++; + start = cursors.diffCursor; + while (getDifferential().getElement().size() > cursors.diffCursor && profileUtilities.pathStartsWith(getDifferential().getElement().get(cursors.diffCursor).getPath(), currentBasePath + ".")) + cursors.diffCursor++; + cursors.diffCursor--; + + this.incrementDebugIndent() + .withBaseLimit( dt.getSnapshot().getElement().size() - 1) + .withDiffLimit(cursors.diffCursor) + .withWebUrl(profileUtilities.getWebUrl(dt, getWebUrl())) + .withContextPathSource(currentBasePath) + .withContextPathTarget(outcome.getPath()).withSlicing(new PathSlicingParams()) /* starting again on the data type, but skip the root */ + . processPaths(new ProfilePathProcessorState(dt.getSnapshot(), 1 /* starting again on the data type, but skip the root */, start, + cursors.contextName, cursors.resultPathBase)); + } + } + start++; + // result.getElement().remove(result.getElement().size()-1); + } else + profileUtilities.checkExtensionDoco(outcome); + } + // now, for each entry in the diff matches, we're going to process the base item + // our processing scope for base is all the children of the current path + int newDiffCursor = cursors.diffCursor; + int newDiffLimit = cursors.diffCursor; + for (int i = start; i < diffMatches.size(); i++) { + // our processing scope for the differential is the item in the list, and all the items before the next one in the list + newDiffCursor = getDifferential().getElement().indexOf(diffMatches.get(i)); + newDiffLimit = profileUtilities.findEndOfElement(getDifferential(), newDiffCursor); + + // now we process the base scope repeatedly for each instance of the item in the differential list + + this + .incrementDebugIndent() + .withBaseLimit(newBaseLimit) + .withDiffLimit(newDiffLimit) + .withProfileName(getProfileName() + profileUtilities.pathTail(diffMatches, i)) + .withSlicing(new PathSlicingParams(true, slicerElement, null)).processPaths(new ProfilePathProcessorState(cursors.base, cursors.baseCursor, newDiffCursor, cursors.contextName, cursors.resultPathBase)); + } + // ok, done with that - next in the base list + cursors.baseCursor = newBaseLimit + 1; + cursors.diffCursor = newDiffLimit + 1; + } + + private void processSimplePathWhereDiffsConstrainTypes(String currentBasePath, List diffMatches, List typeList, ProfilePathProcessorState cursors) { + int start = 0; + int newBaseLimit = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor); + int newDiffCursor = getDifferential().getElement().indexOf(diffMatches.get(0)); + ElementDefinition elementToRemove = null; + boolean shortCut = !typeList.isEmpty() && typeList.get(0).getType() != null; + // we come here whether they are sliced in the diff, or whether the short cut is used. + if (shortCut) { + // this is the short cut method, we've just dived in and specified a type slice. + // in R3 (and unpatched R4, as a workaround right now... + if (!VersionUtilities.isR4Plus(profileUtilities.getContext().getVersion()) || !profileUtilities.isNewSlicingProcessing()) { // newSlicingProcessing is a work around for editorial loop dependency + // we insert a cloned element with the right types at the start of the diffMatches + ElementDefinition ed = new ElementDefinition(); + ed.setPath(profileUtilities.determineTypeSlicePath(diffMatches.get(0).getPath(), currentBasePath)); + for (TypeSlice ts : typeList) + ed.addType().setCode(ts.getType()); + ed.setSlicing(new ElementDefinition.ElementDefinitionSlicingComponent()); + ed.getSlicing().addDiscriminator().setType(ElementDefinition.DiscriminatorType.TYPE).setPath("$this"); + ed.getSlicing().setRules(ElementDefinition.SlicingRules.CLOSED); + ed.getSlicing().setOrdered(false); + diffMatches.add(0, ed); + getDifferential().getElement().add(newDiffCursor, ed); + elementToRemove = ed; + } else { + // as of R4, this changed; if there's no slice, there's no constraint on the slice types, only one the type. + // so the element we insert specifies no types (= all types) allowed in the base, not just the listed type. + // see also discussion here: https://chat.fhir.org/#narrow/stream/179177-conformance/topic/Slicing.20a.20non-repeating.20element + ElementDefinition ed = new ElementDefinition(); + ed.setPath(profileUtilities.determineTypeSlicePath(diffMatches.get(0).getPath(), currentBasePath)); + ed.setSlicing(new ElementDefinition.ElementDefinitionSlicingComponent()); + ed.getSlicing().addDiscriminator().setType(ElementDefinition.DiscriminatorType.TYPE).setPath("$this"); + ed.getSlicing().setRules(ElementDefinition.SlicingRules.CLOSED); + ed.getSlicing().setOrdered(false); + diffMatches.add(0, ed); + getDifferential().getElement().add(newDiffCursor, ed); + elementToRemove = ed; + } + } + int newDiffLimit = profileUtilities.findEndOfElement(getDifferential(), newDiffCursor); + // the first element is setting up the slicing + + if (diffMatches.get(0).getSlicing().hasOrdered()) { + if (diffMatches.get(0).getSlicing().getOrdered()) { + throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGORDERED__TRUE, currentBasePath, getUrl())); + } + } + if (diffMatches.get(0).getSlicing().hasDiscriminator()) { + if (diffMatches.get(0).getSlicing().getDiscriminator().size() != 1) { + throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORCOUNT__1, currentBasePath, getUrl())); + } + if (diffMatches.get(0).getSlicing().getDiscriminatorFirstRep().getType() != ElementDefinition.DiscriminatorType.TYPE) { + throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORTYPE__TYPE, currentBasePath, getUrl())); + } + if (!"$this".equals(diffMatches.get(0).getSlicing().getDiscriminatorFirstRep().getPath())) { + throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORPATH__THIS, currentBasePath, getUrl())); + } + } + // check the slice names too while we're at it... + for (TypeSlice ts : typeList) { + if (ts.getType() != null) { + String tn = profileUtilities.rootName(currentBasePath) + Utilities.capitalize(ts.getType()); + if (!ts.defn.hasSliceName()) { + ts.defn.setSliceName(tn); + } else if (!ts.defn.getSliceName().equals(tn)) { + if (profileUtilities.isAutoFixSliceNames()) { + ts.defn.setSliceName(tn); + } else { + throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_NAME_MUST_BE__BUT_IS_, (!Utilities.noString(getContextPathSource()) ? getContextPathSource() : currentBasePath), tn, ts.defn.getSliceName())); + } + } + if (!ts.defn.hasType()) { + ts.defn.addType().setCode(ts.type); + } else if (ts.defn.getType().size() > 1) { + throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_MORE_THAN_ONE_TYPE_, (!Utilities.noString(getContextPathSource()) ? getContextPathSource() : currentBasePath), tn, ts.defn.typeSummary())); + } else if (!ts.defn.getType().get(0).getCode().equals(ts.type)) { + throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_WRONG_TYPE_, (!Utilities.noString(getContextPathSource()) ? getContextPathSource() : currentBasePath), tn, ts.defn.typeSummary())); + } + } + } + + // ok passed the checks. + // copy the root diff, and then process any children it has + ElementDefinition elementDefinition = + this + .incrementDebugIndent() + .withBaseLimit(newBaseLimit) + .withDiffLimit(newDiffLimit) + .withProfileName(getProfileName() + profileUtilities.pathTail(diffMatches, 0)) + .withSlicing(new PathSlicingParams(true, null, null)) + .processPaths(new ProfilePathProcessorState(cursors.base, cursors.baseCursor, newDiffCursor, + cursors.contextName, cursors.resultPathBase)); + if (elementDefinition == null) + throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.DID_NOT_FIND_TYPE_ROOT_, diffMatches.get(0).getPath())); + // now set up slicing on the e (cause it was wiped by what we called. + elementDefinition.setSlicing(new ElementDefinition.ElementDefinitionSlicingComponent()); + elementDefinition.getSlicing().addDiscriminator().setType(ElementDefinition.DiscriminatorType.TYPE).setPath("$this"); + elementDefinition.getSlicing().setRules(ElementDefinition.SlicingRules.CLOSED); // type slicing is always closed; the differential might call it open, but that just means it's not constraining the slices it doesn't mention + elementDefinition.getSlicing().setOrdered(false); + + start++; + + String fixedType = null; + // now process the siblings, which should each be type constrained - and may also have their own children + // now we process the base scope repeatedly for each instance of the item in the differential list + for (int i = start; i < diffMatches.size(); i++) { + // our processing scope for the differential is the item in the list, and all the items before the next one in the list + if (diffMatches.get(i).getMin() > 0) { + if (diffMatches.size() > i + 1) { + throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.INVALID_SLICING__THERE_IS_MORE_THAN_ONE_TYPE_SLICE_AT__BUT_ONE_OF_THEM__HAS_MIN__1_SO_THE_OTHER_SLICES_CANNOT_EXIST, diffMatches.get(i).getPath(), diffMatches.get(i).getSliceName())); + } else { + elementDefinition.setMin(1); + } + fixedType = profileUtilities.determineFixedType(diffMatches, fixedType, i); + } + newDiffCursor = getDifferential().getElement().indexOf(diffMatches.get(i)); + newDiffLimit = profileUtilities.findEndOfElement(getDifferential(), newDiffCursor); + ElementDefinition typeSliceElement = + this + .incrementDebugIndent() + .withBaseLimit(newBaseLimit) + .withDiffLimit(newDiffLimit) + .withProfileName(getProfileName() + profileUtilities.pathTail(diffMatches, i)) + .withSlicing(new PathSlicingParams(true, elementDefinition, null)) + .processPaths(new ProfilePathProcessorState(cursors.base, cursors.baseCursor, newDiffCursor, cursors.contextName, cursors.resultPathBase)); + if (typeList.size() > start + 1) { + typeSliceElement.setMin(0); + } + } + if (elementToRemove != null) { + getDifferential().getElement().remove(elementToRemove); + newDiffLimit--; + } + if (fixedType != null) { + for (Iterator iter = elementDefinition.getType().iterator(); iter.hasNext(); ) { + ElementDefinition.TypeRefComponent tr = iter.next(); + if (!tr.getCode().equals(fixedType)) { + iter.remove(); + } + } + } + if (!"0".equals(elementDefinition.getMax())) { + // check that there's a slice for each allowed types + Set allowedTypes = profileUtilities.getListOfTypes(elementDefinition); + for (TypeSlice t : typeList) { + if (t.type != null) { + allowedTypes.remove(t.type); + } else if (t.getDefn().hasSliceName() && t.getDefn().getType().size() == 1) { + allowedTypes.remove(t.getDefn().getType().get(0).getCode()); + } + } + if (!allowedTypes.isEmpty()) { + if (currentBasePath.contains("xtension.value")) { + for (Iterator iter = elementDefinition.getType().iterator(); iter.hasNext(); ) { + ElementDefinition.TypeRefComponent tr = iter.next(); + if (allowedTypes.contains(tr.getCode())) { + iter.remove(); + } + } +// System.out.println("!!: Extension Error at "+cpath+": Allowed Types not sliced = "+allowedTypes+". !Extension!!"); +// throw new Error("Extension Error at "+cpath+": Allowed Types not sliced = "+allowedTypes+". !Extension!!"); + + } else { + elementDefinition.getSlicing().setRules(ElementDefinition.SlicingRules.OPEN); + } + } + } + // ok, done with that - next in the base list + cursors.baseCursor = newBaseLimit + 1; + cursors.diffCursor = newDiffLimit + 1; + } + + private ElementDefinition processSimplePathWithOneMatchingElementInDifferential(ElementDefinition currentBase, String currentBasePath, List diffMatches, ProfilePathProcessorState cursors) { + ElementDefinition res; + ElementDefinition template = null; + if (diffMatches.get(0).hasType() && "Reference".equals(diffMatches.get(0).getType().get(0).getWorkingCode()) && !profileUtilities.isValidType(diffMatches.get(0).getType().get(0), currentBase)) { + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.VALIDATION_VAL_ILLEGAL_TYPE_CONSTRAINT, getUrl(), diffMatches.get(0).getPath(), diffMatches.get(0).getType().get(0), currentBase.typeSummary())); + } + String id = diffMatches.get(0).getId(); + String lid = profileUtilities.tail(id); + if (lid.contains("/")) { + // the template comes from the snapshot of the base + profileUtilities.generateIds(getResult().getElement(), getUrl(), getSourceStructureDefinition().getType(), getSourceStructureDefinition()); + String baseId = id.substring(0, id.length() - lid.length()) + lid.substring(0, lid.indexOf("/")); // this is wrong if there's more than one reslice (todo: one thing at a time) + template = profileUtilities.getById(getResult().getElement(), baseId); + + } else if (diffMatches.get(0).hasType() + && diffMatches.get(0).getType().size() == 1 + && diffMatches.get(0).getType().get(0).hasProfile() + && !"Reference".equals(diffMatches.get(0).getType().get(0).getWorkingCode())) { + CanonicalType firstTypeProfile = diffMatches.get(0).getType().get(0).getProfile().get(0); + StructureDefinition firstTypeStructureDefinition = profileUtilities.getContext().fetchResource(StructureDefinition.class, firstTypeProfile.getValue()); + if (firstTypeStructureDefinition == null && profileUtilities.getXver() != null && profileUtilities.getXver().matchingUrl(firstTypeProfile.getValue())) { + switch (profileUtilities.getXver().status(firstTypeProfile.getValue())) { + case BadVersion: + throw new FHIRException("Reference to invalid version in extension url " + firstTypeProfile.getValue()); + case Invalid: + throw new FHIRException("Reference to invalid extension " + firstTypeProfile.getValue()); + case Unknown: + throw new FHIRException("Reference to unknown extension " + firstTypeProfile.getValue()); + case Valid: + firstTypeStructureDefinition = profileUtilities.getXver().makeDefinition(firstTypeProfile.getValue()); + profileUtilities.generateSnapshot(profileUtilities.getContext().fetchTypeDefinition("Extension"), firstTypeStructureDefinition, firstTypeStructureDefinition.getUrl(), getWebUrl(), firstTypeStructureDefinition.getName()); + } + } + if (firstTypeStructureDefinition != null) { + if (!profileUtilities.isMatchingType(firstTypeStructureDefinition, diffMatches.get(0).getType(), firstTypeProfile.getExtensionString(ToolingExtensions.EXT_PROFILE_ELEMENT))) { + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.VALIDATION_VAL_PROFILE_WRONGTYPE2, firstTypeStructureDefinition.getUrl(), diffMatches.get(0).getPath(), firstTypeStructureDefinition.getType(), firstTypeProfile.getValue(), diffMatches.get(0).getType().get(0).getWorkingCode())); + } + if (profileUtilities.isGenerating(firstTypeStructureDefinition)) { + // this is a special case, because we're only going to access the first element, and we can rely on the fact that it's already populated. + // but we check anyway + if (firstTypeStructureDefinition.getSnapshot().getElementFirstRep().isEmpty()) { + throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ATTEMPT_TO_USE_A_SNAPSHOT_ON_PROFILE__AS__BEFORE_IT_IS_GENERATED, firstTypeStructureDefinition.getUrl(), "Source for first element")); + } + } else if (!firstTypeStructureDefinition.hasSnapshot()) { + StructureDefinition sdb = profileUtilities.getContext().fetchResource(StructureDefinition.class, firstTypeStructureDefinition.getBaseDefinition()); + if (sdb == null) + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.UNABLE_TO_FIND_BASE__FOR_, firstTypeStructureDefinition.getBaseDefinition(), firstTypeStructureDefinition.getUrl())); + profileUtilities.checkNotGenerating(sdb, "an extension base"); + profileUtilities.generateSnapshot(sdb, firstTypeStructureDefinition, firstTypeStructureDefinition.getUrl(), (sdb.hasUserData("path")) ? Utilities.extractBaseUrl(sdb.getUserString("path")) : getWebUrl(), firstTypeStructureDefinition.getName()); + } + ElementDefinition src; + if (firstTypeProfile.hasExtension(ToolingExtensions.EXT_PROFILE_ELEMENT)) { + src = null; + String eid = firstTypeProfile.getExtensionString(ToolingExtensions.EXT_PROFILE_ELEMENT); + for (ElementDefinition t : firstTypeStructureDefinition.getSnapshot().getElement()) { + if (eid.equals(t.getId())) + src = t; + } + if (src == null) + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.UNABLE_TO_FIND_ELEMENT__IN_, eid, firstTypeProfile.getValue())); + } else + src = firstTypeStructureDefinition.getSnapshot().getElement().get(0); + template = src.copy().setPath(currentBase.getPath()); + template.setSliceName(null); + // temporary work around + if (!"Extension".equals(diffMatches.get(0).getType().get(0).getCode())) { + template.setMin(currentBase.getMin()); + template.setMax(currentBase.getMax()); + } + } + } + if (template == null) + template = currentBase.copy(); + else + // some of what's in currentBase overrides template + template = profileUtilities.fillOutFromBase(template, currentBase); + + ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), template); + outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource())); + + res = outcome; + profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl()); + if (diffMatches.get(0).hasSliceName()) { + outcome.setSliceName(diffMatches.get(0).getSliceName()); + if (!diffMatches.get(0).hasMin() && (diffMatches.size() > 1 || getSlicing().getElementDefinition()== null || getSlicing().getElementDefinition().getSlicing().getRules() != ElementDefinition.SlicingRules.CLOSED) && !currentBase.hasSliceName()) { + if (!currentBasePath.endsWith("xtension.value[x]")) { // hack work around for problems with snapshots in official releases + outcome.setMin(0); + } + } + } + profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), getProfileName(), isTrimDifferential(), getUrl(), getSourceStructureDefinition(), getDerived()); + profileUtilities.removeStatusExtensions(outcome); +// if (outcome.getPath().endsWith("[x]") && outcome.getType().size() == 1 && !outcome.getType().get(0).getCode().equals("*") && !diffMatches.get(0).hasSlicing()) // if the base profile allows multiple types, but the profile only allows one, rename it +// outcome.setPath(outcome.getPath().substring(0, outcome.getPath().length()-3)+Utilities.capitalize(outcome.getType().get(0).getCode())); + outcome.setSlicing(null); + if (cursors.resultPathBase == null) + cursors.resultPathBase = outcome.getPath(); + else if (!outcome.getPath().startsWith(cursors.resultPathBase)) + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH)); + getResult().getElement().add(outcome); + cursors.baseCursor++; + cursors.diffCursor = getDifferential().getElement().indexOf(diffMatches.get(0)) + 1; + if (getDiffLimit() >= cursors.diffCursor && outcome.getPath().contains(".") && (profileUtilities.isDataType(outcome.getType()) || profileUtilities.isBaseResource(outcome.getType()) || outcome.hasContentReference())) { // don't want to do this for the root, since that's base, and we're already processing it + if (profileUtilities.pathStartsWith(getDifferential().getElement().get(cursors.diffCursor).getPath(), diffMatches.get(0).getPath() + ".") && !profileUtilities.baseWalksInto(cursors.base.getElement(), cursors.baseCursor)) { + if (outcome.getType().size() > 1) { + if (outcome.getPath().endsWith("[x]") && !diffMatches.get(0).getPath().endsWith("[x]")) { + String en = profileUtilities.tail(outcome.getPath()); + String tn = profileUtilities.tail(diffMatches.get(0).getPath()); + String t = tn.substring(en.length() - 3); + if (profileUtilities.isPrimitive(Utilities.uncapitalize(t))) + t = Utilities.uncapitalize(t); + List ntr = profileUtilities.getByTypeName(outcome.getType(), t); // keep any additional information + if (ntr.isEmpty()) + ntr.add(new ElementDefinition.TypeRefComponent().setCode(t)); + outcome.getType().clear(); + outcome.getType().addAll(ntr); + } + if (outcome.getType().size() > 1) + for (ElementDefinition.TypeRefComponent t : outcome.getType()) { + if (!t.getCode().equals("Reference")) { + boolean nonExtension = false; + for (ElementDefinition ed : diffMatches) + if (ed != diffMatches.get(0) && !ed.getPath().endsWith(".extension")) + nonExtension = true; + if (nonExtension) + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants._HAS_CHILDREN__AND_MULTIPLE_TYPES__IN_PROFILE_, diffMatches.get(0).getPath(), getDifferential().getElement().get(cursors.diffCursor).getPath(), profileUtilities.typeCode(outcome.getType()), getProfileName())); + } + } + } + int start = cursors.diffCursor; + while (cursors.diffCursor <= getDiffLimit() && getDifferential().getElement().size() > cursors.diffCursor && profileUtilities.pathStartsWith(getDifferential().getElement().get(cursors.diffCursor).getPath(), diffMatches.get(0).getPath() + ".")) + cursors.diffCursor++; + if (outcome.hasContentReference()) { + ProfileUtilities.ElementDefinitionResolution target = profileUtilities.getElementById(getSourceStructureDefinition(), cursors.base.getElement(), outcome.getContentReference()); + if (target == null) + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.UNABLE_TO_RESOLVE_REFERENCE_TO_, outcome.getContentReference())); + profileUtilities.replaceFromContentReference(outcome, target.getElement()); + if (target.getSource() != getSourceStructureDefinition()) { + cursors.base = target.getSource().getSnapshot(); + int newBaseCursor = cursors.base.getElement().indexOf(target.getElement()) + 1; + int newBaseLimit = newBaseCursor; + while (newBaseLimit < cursors.base.getElement().size() && cursors.base.getElement().get(newBaseLimit).getPath().startsWith(target.getElement().getPath() + ".")) + newBaseLimit++; + + this + .incrementDebugIndent() + .withBaseLimit(newBaseLimit - 1) + .withDiffLimit(cursors.diffCursor - 1) + .withContextPathSource(target.getElement().getPath()) + .withContextPathTarget(diffMatches.get(0).getPath()).withRedirector(profileUtilities.redirectorStack(getRedirector(), outcome, currentBasePath)) + .withSourceStructureDefinition(target.getSource()) + .withSlicing(new PathSlicingParams()).processPaths(new ProfilePathProcessorState(cursors.base, newBaseCursor, start - 1, cursors.contextName, cursors.resultPathBase)); + } else { + final int newBaseCursor = cursors.base.getElement().indexOf(target.getElement()) + 1; + int newBaseLimit = newBaseCursor; + while (newBaseLimit < cursors.base.getElement().size() && cursors.base.getElement().get(newBaseLimit).getPath().startsWith(target.getElement().getPath() + ".")) + newBaseLimit++; + + this + .incrementDebugIndent() + .withBaseLimit(newBaseLimit - 1) + .withDiffLimit(cursors.diffCursor - 1) + .withContextPathSource(target.getElement().getPath()) + .withContextPathTarget(diffMatches.get(0).getPath()) + .withRedirector(profileUtilities.redirectorStack(getRedirector(), outcome, currentBasePath)) + .withSlicing(new PathSlicingParams()).processPaths( + new ProfilePathProcessorState(cursors.base, newBaseCursor, start - 1, cursors.contextName, cursors.resultPathBase)); + } + } else { + StructureDefinition dt = outcome.getType().size() == 1 ? profileUtilities.getProfileForDataType(outcome.getType().get(0), getWebUrl(), getDerived()) : profileUtilities.getProfileForDataType("Element"); + if (dt == null) + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants._HAS_CHILDREN__FOR_TYPE__IN_PROFILE__BUT_CANT_FIND_TYPE, diffMatches.isEmpty() ? "??" : diffMatches.get(0).getPath(), getDifferential().getElement().get(cursors.diffCursor).getPath(), profileUtilities.typeCode(outcome.getType()), getProfileName())); + cursors.contextName = dt.getUrl(); + + this + .incrementDebugIndent() + .withBaseLimit(dt.getSnapshot().getElement().size() - 1) + .withDiffLimit(cursors.diffCursor - 1) + .withWebUrl( profileUtilities.getWebUrl(dt, getWebUrl())) + .withProfileName(getProfileName() + profileUtilities.pathTail(diffMatches, 0)) + .withContextPathSource(diffMatches.get(0).getPath()).withContextPathTarget(outcome.getPath()).withRedirector(new ArrayList()) + .withSlicing(new PathSlicingParams()). /* starting again on the data type, but skip the root */ + processPaths(new ProfilePathProcessorState(dt.getSnapshot(), 1 /* starting again on the data type, but skip the root */, start, + cursors.contextName, cursors.resultPathBase)); + } + } + } + return res; + } + + private void processSimplePathWithEmptyDiffMatches(ElementDefinition currentBase, String currentBasePath, List diffMatches, ProfilePathProcessorState cursors) { + ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy()); + outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource())); + profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl()); + profileUtilities.updateConstraintSources(outcome, getSourceStructureDefinition().getUrl()); + profileUtilities.markDerived(outcome); + if (cursors.resultPathBase == null) + cursors.resultPathBase = outcome.getPath(); + else if (!outcome.getPath().startsWith(cursors.resultPathBase)) + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH__OUTCOMEGETPATH___RESULTPATHBASE__, outcome.getPath(), cursors.resultPathBase)); + getResult().getElement().add(outcome); + if (profileUtilities.hasInnerDiffMatches(getDifferential(), currentBasePath, cursors.diffCursor, getDiffLimit(), cursors.base.getElement(), true)) { + // well, the profile walks into this, so we need to as well + // did we implicitly step into a new type? + if (profileUtilities.baseHasChildren(cursors.base, currentBase)) { // not a new type here + + this.incrementDebugIndent().withSlicing(new PathSlicingParams()). processPaths( new ProfilePathProcessorState(cursors.base, cursors.baseCursor + 1, cursors.diffCursor, cursors.contextName, cursors.resultPathBase)); + cursors.baseCursor = profileUtilities.indexOfFirstNonChild(cursors.base, currentBase, cursors.baseCursor + 1, getBaseLimit()); + } + else { + if (outcome.getType().size() == 0 && !outcome.hasContentReference()) { + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants._HAS_NO_CHILDREN__AND_NO_TYPES_IN_PROFILE_, currentBasePath, getDifferential().getElement().get(cursors.diffCursor).getPath(), getProfileName())); + } + boolean nonExtension = false; + if (outcome.getType().size() > 1) { + for (ElementDefinition.TypeRefComponent t : outcome.getType()) { + if (!t.getWorkingCode().equals("Reference")) { + for (ElementDefinition ed : diffMatches) { + if (ed != diffMatches.get(0) && !ed.getPath().endsWith(".extension")) { + nonExtension = true; + } + } + } + } + } + int start = cursors.diffCursor; + while (getDifferential().getElement().size() > cursors.diffCursor && profileUtilities.pathStartsWith(getDifferential().getElement().get(cursors.diffCursor).getPath(), currentBasePath + ".")) + cursors.diffCursor++; + if (nonExtension) { + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants._HAS_CHILDREN__AND_MULTIPLE_TYPES__IN_PROFILE_, currentBasePath, getDifferential().getElement().get(cursors.diffCursor).getPath(), profileUtilities.typeCode(outcome.getType()), getProfileName())); + } + if (outcome.hasContentReference()) { + ProfileUtilities.ElementDefinitionResolution tgt = profileUtilities.getElementById(getSourceStructureDefinition(), cursors.base.getElement(), outcome.getContentReference()); + if (tgt == null) + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.UNABLE_TO_RESOLVE_REFERENCE_TO_, outcome.getContentReference())); + profileUtilities.replaceFromContentReference(outcome, tgt.getElement()); + if (tgt.getSource() != getSourceStructureDefinition()) { + cursors.base = tgt.getSource().getSnapshot(); + int newBaseCursor = cursors.base.getElement().indexOf(tgt.getElement()) + 1; + int newBaseLimit = newBaseCursor; + while (newBaseLimit < cursors.base.getElement().size() && cursors.base.getElement().get(newBaseLimit).getPath().startsWith(tgt.getElement().getPath() + ".")) + newBaseLimit++; + + this + .incrementDebugIndent() + .withBaseLimit(newBaseLimit - 1) + .withDiffLimit(cursors.diffCursor - 1) + .withContextPathSource(tgt.getElement().getPath()) + .withContextPathTarget(diffMatches.get(0).getPath()) + .withRedirector(profileUtilities.redirectorStack(getRedirector(), outcome, currentBasePath)) + .withSourceStructureDefinition(tgt.getSource()) + .withSlicing(new PathSlicingParams()).processPaths( + new ProfilePathProcessorState(cursors.base, newBaseCursor, start - 1, cursors.contextName, cursors.resultPathBase)); + } else { + int newBaseCursor = cursors.base.getElement().indexOf(tgt.getElement()) + 1; + int newBaseLimit = newBaseCursor; + while (newBaseLimit < cursors.base.getElement().size() && cursors.base.getElement().get(newBaseLimit).getPath().startsWith(tgt.getElement().getPath() + ".")) + newBaseLimit++; + System.out.println("Test!"); + + this + .incrementDebugIndent() + .withBaseLimit(newBaseLimit - 1) + .withDiffLimit(cursors.diffCursor - 1) + .withContextPathSource(tgt.getElement().getPath()) + .withContextPathTarget(outcome.getPath()) + .withRedirector(profileUtilities.redirectorStack(getRedirector(), outcome, currentBasePath)).withSlicing(new PathSlicingParams()).processPaths( + new ProfilePathProcessorState(cursors.base, newBaseCursor, start, cursors.contextName, cursors.resultPathBase)); + } + } else { + StructureDefinition dt = outcome.getType().size() > 1 ? profileUtilities.getContext().fetchTypeDefinition("Element") : profileUtilities.getProfileForDataType(outcome.getType().get(0), getWebUrl(), getDerived()); + if (dt == null) { + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.UNKNOWN_TYPE__AT_, outcome.getType().get(0), currentBasePath)); + } + cursors.contextName = dt.getUrl(); + if (getRedirector() == null || getRedirector().isEmpty()) { + + this + .incrementDebugIndent() + .withBaseLimit(dt.getSnapshot().getElement().size() - 1) + .withDiffLimit(cursors.diffCursor - 1) + .withWebUrl(profileUtilities.getWebUrl(dt, getWebUrl())) + .withContextPathSource(currentBasePath) + .withContextPathTarget(outcome.getPath()) + .withSlicing(new PathSlicingParams()).processPaths( /* starting again on the data type, but skip the root */ + new ProfilePathProcessorState(dt.getSnapshot(), 1 /* starting again on the data type, but skip the root */, start, + cursors.contextName, cursors.resultPathBase)); + } else { + + this + .incrementDebugIndent() + .withBaseLimit(dt.getSnapshot().getElement().size() - 1) + .withDiffLimit(cursors.diffCursor - 1) + .withWebUrl(profileUtilities.getWebUrl(dt, getWebUrl())) + .withContextPathSource(currentBasePath) + .withContextPathTarget( outcome.getPath()) + .withRedirector(profileUtilities.redirectorStack(getRedirector(), currentBase, currentBasePath)).withSlicing(new PathSlicingParams()).processPaths( /* starting again on the data type, but skip the root */ + new ProfilePathProcessorState(dt.getSnapshot(), 1 /* starting again on the data type, but skip the root */, start, + cursors.contextName, cursors.resultPathBase)); + } + } + } + } + cursors.baseCursor++; + } + + private void processPathWithSlicedBase( + ElementDefinition currentBase, + String currentBasePath, + List diffMatches, List typeList, + final ProfilePathProcessorState cursors + ) { + // the item is already sliced in the base profile. + // here's the rules + // 1. irrespective of whether the slicing is ordered or not, the definition order must be maintained + // 2. slice element names have to match. + // 3. new slices must be introduced at the end + // corallory: you can't re-slice existing slices. is that ok? + + // we're going to need this: + String path = currentBase.getPath(); + + if (diffMatches.isEmpty()) { + processPathWithSlicedBaseAndEmptyDiffMatches(currentBase, currentBasePath, diffMatches, cursors, path); + } + else if (profileUtilities.diffsConstrainTypes(diffMatches, currentBasePath, typeList)) + { + processPathWithSlicedBaseWhereDiffsConstrainTypes(currentBasePath, diffMatches, typeList, cursors); + } + else + { + processPathWithSlicedBaseDefault(currentBase, currentBasePath, diffMatches, cursors, path); + } + } + + private void processPathWithSlicedBaseDefault(ElementDefinition currentBase, String currentBasePath, List diffMatches, ProfilePathProcessorState cursors, String path) { + // first - check that the slicing is ok + boolean closed = currentBase.getSlicing().getRules() == ElementDefinition.SlicingRules.CLOSED; + int diffpos = 0; + if (diffMatches.get(0).hasSlicing()) { // it might be null if the differential doesn't want to say anything about slicing +// if (!isExtension) +// diffpos++; // if there's a slice on the first, we'll ignore any content it has + ElementDefinition.ElementDefinitionSlicingComponent dSlice = diffMatches.get(0).getSlicing(); + ElementDefinition.ElementDefinitionSlicingComponent bSlice = currentBase.getSlicing(); + if (dSlice.hasOrderedElement() && bSlice.hasOrderedElement() && !profileUtilities.orderMatches(dSlice.getOrderedElement(), bSlice.getOrderedElement())) + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.SLICING_RULES_ON_DIFFERENTIAL__DO_NOT_MATCH_THOSE_ON_BASE___ORDER___, profileUtilities.summarizeSlicing(dSlice), profileUtilities.summarizeSlicing(bSlice), path, cursors.contextName)); + if (!profileUtilities.discriminatorMatches(dSlice.getDiscriminator(), bSlice.getDiscriminator())) + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.SLICING_RULES_ON_DIFFERENTIAL__DO_NOT_MATCH_THOSE_ON_BASE___DISCIMINATOR___, profileUtilities.summarizeSlicing(dSlice), profileUtilities.summarizeSlicing(bSlice), path, cursors.contextName)); + if (!currentBase.isChoice() && !profileUtilities.ruleMatches(dSlice.getRules(), bSlice.getRules())) + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.SLICING_RULES_ON_DIFFERENTIAL__DO_NOT_MATCH_THOSE_ON_BASE___RULE___, profileUtilities.summarizeSlicing(dSlice), profileUtilities.summarizeSlicing(bSlice), path, cursors.contextName)); + } + ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy()); + outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource())); + profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl()); + if (diffMatches.get(0).hasSlicing() || !diffMatches.get(0).hasSliceName()) { + profileUtilities.updateFromSlicing(outcome.getSlicing(), diffMatches.get(0).getSlicing()); + profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), getProfileName(), closed, getUrl(), getSourceStructureDefinition(), getDerived()); // if there's no slice, we don't want to update the unsliced description + profileUtilities.removeStatusExtensions(outcome); + } else if (!diffMatches.get(0).hasSliceName()) { + diffMatches.get(0).setUserData(profileUtilities.GENERATED_IN_SNAPSHOT, outcome); // because of updateFromDefinition isn't called + } + + getResult().getElement().add(outcome); + + if (!diffMatches.get(0).hasSliceName()) { // it's not real content, just the slice + diffpos++; + } + if (profileUtilities.hasInnerDiffMatches(getDifferential(), currentBasePath, cursors.diffCursor, getDiffLimit(), cursors.base.getElement(), false)) { + int newBaseLimit = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor); + int ndx = getDifferential().getElement().indexOf(diffMatches.get(0)); + int newDiffCursor = ndx + (diffMatches.get(0).hasSlicing() ? 1 : 0); + int newDiffLimit = profileUtilities.findEndOfElement(getDifferential(), ndx); + if (newBaseLimit == cursors.baseCursor) { + if (cursors.base.getElement().get(cursors.baseCursor).getType().size() != 1) { + throw new Error(profileUtilities.getContext().formatMessage(I18nConstants.DIFFERENTIAL_WALKS_INTO____BUT_THE_BASE_DOES_NOT_AND_THERE_IS_NOT_A_SINGLE_FIXED_TYPE_THE_TYPE_IS__THIS_IS_NOT_HANDLED_YET, currentBasePath, diffMatches.get(0).toString(), cursors.base.getElement().get(cursors.baseCursor).typeSummary())); + } + StructureDefinition dt = profileUtilities.getProfileForDataType(cursors.base.getElement().get(cursors.baseCursor).getType().get(0), getWebUrl(), getDerived()); + if (dt == null) { + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.UNKNOWN_TYPE__AT_, outcome.getType().get(0), diffMatches.get(0).getPath())); + } + cursors.contextName = dt.getUrl(); + while (getDifferential().getElement().size() > cursors.diffCursor && profileUtilities.pathStartsWith(getDifferential().getElement().get(cursors.diffCursor).getPath(), currentBasePath + ".")) + cursors.diffCursor++; + + this + .incrementDebugIndent() + .withBaseLimit(dt.getSnapshot().getElement().size() - 1) + .withDiffLimit(newDiffLimit) + .withWebUrl(profileUtilities.getWebUrl(dt, getWebUrl())) + .withContextPathSource(currentBasePath).withContextPathTarget(outcome.getPath()) + .withSlicing(new PathSlicingParams()).processPaths( + new ProfilePathProcessorState(dt.getSnapshot(), 1, newDiffCursor, + cursors.contextName, cursors.resultPathBase)); + } else { + + this + .incrementDebugIndent() + .withBaseLimit(newBaseLimit) + .withDiffLimit(newDiffLimit) + .withProfileName(getProfileName() + profileUtilities.pathTail(diffMatches, 0)) + .withRedirector(null).withSlicing(new PathSlicingParams()).processPaths( + new ProfilePathProcessorState(cursors.base, cursors.baseCursor + 1, newDiffCursor, + cursors.contextName, cursors.resultPathBase)); + } +// throw new Error("Not done yet"); +// } else if (currentBase.getType().get(0).getCode().equals("BackboneElement") && diffMatches.size() > 0 && diffMatches.get(0).hasSliceName()) { + } else if (currentBase.getType().get(0).getCode().equals("BackboneElement")) { + // We need to copy children of the backbone element before we start messing around with slices + int newBaseLimit = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor); + for (int i = cursors.baseCursor + 1; i <= newBaseLimit; i++) { + outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), cursors.base.getElement().get(i).copy()); + getResult().getElement().add(outcome); + } + } + + // now, we have two lists, base and diff. we're going to work through base, looking for matches in diff. + List baseMatches = profileUtilities.getSiblings(cursors.base.getElement(), currentBase); + for (ElementDefinition baseItem : baseMatches) { + cursors.baseCursor = cursors.base.getElement().indexOf(baseItem); + outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), baseItem.copy()); + profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl()); + outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource())); + outcome.setSlicing(null); + if (!outcome.getPath().startsWith(cursors.resultPathBase)) + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH)); + if (diffpos < diffMatches.size() && diffMatches.get(diffpos).hasSliceName() && diffMatches.get(diffpos).getSliceName().equals(outcome.getSliceName())) { + // if there's a diff, we update the outcome with diff + // no? updateFromDefinition(outcome, diffMatches.get(diffpos), profileName, closed, url); + //then process any children + int newBaseLimit = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor); + int newDiffCursor = getDifferential().getElement().indexOf(diffMatches.get(diffpos)); + int newDiffLimit = profileUtilities.findEndOfElement(getDifferential(), newDiffCursor); + // now we process the base scope repeatedly for each instance of the item in the differential list + + this + .incrementDebugIndent() + .withBaseLimit(newBaseLimit) + .withDiffLimit(newDiffLimit) + .withProfileName(getProfileName() + profileUtilities.pathTail(diffMatches, diffpos)) + .withTrimDifferential(closed) + .withSlicing(new PathSlicingParams(true, null, null)).processPaths( + new ProfilePathProcessorState(cursors.base, cursors.baseCursor, newDiffCursor, cursors.contextName, cursors.resultPathBase)); + // ok, done with that - now set the cursors for if this is the end + cursors.baseCursor = newBaseLimit; + cursors.diffCursor = newDiffLimit + 1; + diffpos++; + } else { + getResult().getElement().add(outcome); + cursors.baseCursor++; + // just copy any children on the base + while (cursors.baseCursor < cursors.base.getElement().size() && cursors.base.getElement().get(cursors.baseCursor).getPath().startsWith(path) && !cursors.base.getElement().get(cursors.baseCursor).getPath().equals(path)) { + outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), cursors.base.getElement().get(cursors.baseCursor).copy()); + outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource())); + if (!outcome.getPath().startsWith(cursors.resultPathBase)) + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH)); + outcome.setUserData(profileUtilities.BASE_PATH, outcome.getPath()); + outcome.setUserData(profileUtilities.BASE_MODEL, getSourceStructureDefinition().getUrl()); + getResult().getElement().add(outcome); + cursors.baseCursor++; + } + //Lloyd - add this for test T15 + cursors.baseCursor--; + } + } + // finally, we process any remaining entries in diff, which are new (and which are only allowed if the base wasn't closed + if (closed && diffpos < diffMatches.size()) { + // this is a problem, unless we're on a polymorhpic type and we're going to constrain a slice that actually implicitly exists + if (!currentBase.getPath().endsWith("[x]")) { + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.THE_BASE_SNAPSHOT_MARKS_A_SLICING_AS_CLOSED_BUT_THE_DIFFERENTIAL_TRIES_TO_EXTEND_IT_IN__AT__, getProfileName(), path, currentBasePath)); + } + } + if (diffpos != diffMatches.size()) { + while (diffpos < diffMatches.size()) { + ElementDefinition diffItem = diffMatches.get(diffpos); + for (ElementDefinition baseItem : baseMatches) + if (baseItem.getSliceName().equals(diffItem.getSliceName())) + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.NAMED_ITEMS_ARE_OUT_OF_ORDER_IN_THE_SLICE)); + outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy()); + // outcome = updateURLs(url, diffItem.copy()); + outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource())); + profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl()); + outcome.setSlicing(null); + outcome.setMin(0); // we're in a slice, so it's only a mandatory if it's explicitly marked so + if (!outcome.getPath().startsWith(cursors.resultPathBase)) + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH)); + getResult().getElement().add(outcome); + profileUtilities.updateFromDefinition(outcome, diffItem, getProfileName(), isTrimDifferential(), getUrl(), getSourceStructureDefinition(), getDerived()); + profileUtilities.removeStatusExtensions(outcome); + // --- LM Added this + cursors.diffCursor = getDifferential().getElement().indexOf(diffItem) + 1; + if (!outcome.getType().isEmpty() && (/*outcome.getType().get(0).getCode().equals("Extension") || */getDifferential().getElement().size() > cursors.diffCursor) && outcome.getPath().contains(".")/* && isDataType(outcome.getType())*/) { // don't want to do this for the root, since that's base, and we're already processing it + if (!profileUtilities.baseWalksInto(cursors.base.getElement(), cursors.baseCursor)) { + if (getDifferential().getElement().size() > cursors.diffCursor && profileUtilities.pathStartsWith(getDifferential().getElement().get(cursors.diffCursor).getPath(), diffMatches.get(0).getPath() + ".")) { + if (outcome.getType().size() > 1) + for (ElementDefinition.TypeRefComponent t : outcome.getType()) { + if (!t.getCode().equals("Reference")) + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants._HAS_CHILDREN__AND_MULTIPLE_TYPES__IN_PROFILE_, diffMatches.get(0).getPath(), getDifferential().getElement().get(cursors.diffCursor).getPath(), profileUtilities.typeCode(outcome.getType()), getProfileName())); + } + ElementDefinition.TypeRefComponent t = outcome.getType().get(0); + if (t.getCode().equals("BackboneElement")) { + int baseStart = cursors.base.getElement().indexOf(currentBase) + 1; + int baseMax = baseStart + 1; + while (baseMax < cursors.base.getElement().size() && cursors.base.getElement().get(baseMax).getPath().startsWith(currentBase.getPath() + ".")) + baseMax++; + int start = cursors.diffCursor; + while (getDifferential().getElement().size() > cursors.diffCursor && profileUtilities.pathStartsWith(getDifferential().getElement().get(cursors.diffCursor).getPath(), diffMatches.get(0).getPath() + ".")) + cursors.diffCursor++; + + this.incrementDebugIndent().withBaseLimit(baseMax - 1) + .withDiffLimit(cursors.diffCursor - 1) + .withProfileName(getProfileName() + profileUtilities.pathTail(diffMatches, 0)) + .withContextPathSource(cursors.base.getElement().get(0).getPath()) + .withContextPathTarget(cursors.base.getElement().get(0).getPath()) + .withSlicing(new PathSlicingParams()).processPaths( + new ProfilePathProcessorState(cursors.base, baseStart, start - 1, + cursors.contextName, cursors.resultPathBase)); + } else { + StructureDefinition dt = profileUtilities.getProfileForDataType(outcome.getType().get(0), getWebUrl(), getDerived()); + // if (t.getCode().equals("Extension") && t.hasProfile() && !t.getProfile().contains(":")) { + // lloydfix dt = + // } + if (dt == null) + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants._HAS_CHILDREN__FOR_TYPE__IN_PROFILE__BUT_CANT_FIND_TYPE, diffMatches.get(0).getPath(), getDifferential().getElement().get(cursors.diffCursor).getPath(), profileUtilities.typeCode(outcome.getType()), getProfileName())); + cursors.contextName = dt.getUrl(); + int start = cursors.diffCursor; + while (getDifferential().getElement().size() > cursors.diffCursor && profileUtilities.pathStartsWith(getDifferential().getElement().get(cursors.diffCursor).getPath(), diffMatches.get(0).getPath() + ".")) + cursors.diffCursor++; + + this + .incrementDebugIndent() + .withBaseLimit(dt.getSnapshot().getElement().size() - 1) + .withDiffLimit(cursors.diffCursor - 1) + .withWebUrl(profileUtilities.getWebUrl(dt, getWebUrl())) + .withProfileName(getProfileName() + profileUtilities.pathTail(diffMatches, 0)) + .withContextPathSource(diffMatches.get(0).getPath()).withContextPathTarget(outcome.getPath()).withSlicing(new PathSlicingParams()).processPaths( /* starting again on the data type, but skip the root */ + new ProfilePathProcessorState(dt.getSnapshot(), 1 /* starting again on the data type, but skip the root */, start - 1, + cursors.contextName, cursors.resultPathBase)); + } + } + } + } + // --- + diffpos++; + } + } + cursors.baseCursor++; + } + + private void processPathWithSlicedBaseWhereDiffsConstrainTypes(String currentBasePath, List diffMatches, List typeList, ProfilePathProcessorState cursors) { + int start = 0; + int newBaseLimit = profileUtilities.findEndOfElement(cursors.base, cursors.baseCursor); + int newDiffCursor = getDifferential().getElement().indexOf(diffMatches.get(0)); + ElementDefinition elementToRemove = null; + boolean shortCut = (!typeList.isEmpty() && typeList.get(0).type != null) || (diffMatches.get(0).hasSliceName() && !diffMatches.get(0).hasSlicing()); + // we come here whether they are sliced in the diff, or whether the short cut is used. + if (shortCut) { + // this is the short cut method, we've just dived in and specified a type slice. + // in R3 (and unpatched R4, as a workaround right now... + if (!VersionUtilities.isR4Plus(profileUtilities.getContext().getVersion()) || !profileUtilities.isNewSlicingProcessing()) { // newSlicingProcessing is a work around for editorial loop dependency + // we insert a cloned element with the right types at the start of the diffMatches + ElementDefinition ed = new ElementDefinition(); + ed.setPath(profileUtilities.determineTypeSlicePath(diffMatches.get(0).getPath(), currentBasePath)); + for (TypeSlice ts : typeList) + ed.addType().setCode(ts.type); + ed.setSlicing(new ElementDefinition.ElementDefinitionSlicingComponent()); + ed.getSlicing().addDiscriminator().setType(ElementDefinition.DiscriminatorType.TYPE).setPath("$this"); + ed.getSlicing().setRules(ElementDefinition.SlicingRules.CLOSED); + ed.getSlicing().setOrdered(false); + diffMatches.add(0, ed); + getDifferential().getElement().add(newDiffCursor, ed); + elementToRemove = ed; + } else { + // as of R4, this changed; if there's no slice, there's no constraint on the slice types, only one the type. + // so the element we insert specifies no types (= all types) allowed in the base, not just the listed type. + // see also discussion here: https://chat.fhir.org/#narrow/stream/179177-conformance/topic/Slicing.20a.20non-repeating.20element + ElementDefinition ed = new ElementDefinition(); + ed.setPath(profileUtilities.determineTypeSlicePath(diffMatches.get(0).getPath(), currentBasePath)); + ed.setSlicing(new ElementDefinition.ElementDefinitionSlicingComponent()); + ed.getSlicing().addDiscriminator().setType(ElementDefinition.DiscriminatorType.TYPE).setPath("$this"); + ed.getSlicing().setRules(ElementDefinition.SlicingRules.CLOSED); + ed.getSlicing().setOrdered(false); + diffMatches.add(0, ed); + getDifferential().getElement().add(newDiffCursor, ed); + elementToRemove = ed; + } + } + int newDiffLimit = profileUtilities.findEndOfElement(getDifferential(), newDiffCursor); + // the first element is setting up the slicing + + if (diffMatches.get(0).getSlicing().hasOrdered()) { + if (diffMatches.get(0).getSlicing().getOrdered()) { + throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGORDERED__TRUE, currentBasePath, getUrl())); + } + } + if (diffMatches.get(0).getSlicing().hasDiscriminator()) { + if (diffMatches.get(0).getSlicing().getDiscriminator().size() != 1) { + throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORCOUNT__1, currentBasePath, getUrl())); + } + if (diffMatches.get(0).getSlicing().getDiscriminatorFirstRep().getType() != ElementDefinition.DiscriminatorType.TYPE) { + throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORTYPE__TYPE, currentBasePath, getUrl())); + } + if (!"$this".equals(diffMatches.get(0).getSlicing().getDiscriminatorFirstRep().getPath())) { + throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORPATH__THIS, currentBasePath, getUrl())); + } + } + // check the slice names too while we're at it... + for (TypeSlice ts : typeList) { + if (ts.type != null) { + String tn = profileUtilities.rootName(currentBasePath) + Utilities.capitalize(ts.type); + if (!ts.defn.hasSliceName()) { + ts.defn.setSliceName(tn); + } else if (!ts.defn.getSliceName().equals(tn)) { + throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_NAME_MUST_BE__BUT_IS_, (!Utilities.noString(getContextPathSource()) ? getContextPathSource() : currentBasePath), tn, ts.defn.getSliceName())); + } + if (!ts.defn.hasType()) { + ts.defn.addType().setCode(ts.type); + } else if (ts.defn.getType().size() > 1) { + throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_MORE_THAN_ONE_TYPE_, (!Utilities.noString(getContextPathSource()) ? getContextPathSource() : currentBasePath), tn, ts.defn.typeSummary())); + } else if (!ts.defn.getType().get(0).getCode().equals(ts.type)) { + throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_WRONG_TYPE_, (!Utilities.noString(getContextPathSource()) ? getContextPathSource() : currentBasePath), tn, ts.defn.typeSummary())); + } + } + } + + // ok passed the checks. + // copy the root diff, and then process any children it has + ElementDefinition e = + this + .incrementDebugIndent() + .withBaseLimit(newBaseLimit) + .withDiffLimit(newDiffLimit) + .withProfileName(getProfileName() + profileUtilities.pathTail(diffMatches,0)) + .withSlicing(new PathSlicingParams(true, null, currentBasePath)).processPaths( + new ProfilePathProcessorState(cursors.base, cursors.baseCursor, newDiffCursor, + cursors.contextName, cursors.resultPathBase)); + if (e == null) + throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.DID_NOT_FIND_TYPE_ROOT_, diffMatches.get(0).getPath())); + // now set up slicing on the e (cause it was wiped by what we called. + e.setSlicing(new ElementDefinition.ElementDefinitionSlicingComponent()); + e.getSlicing().addDiscriminator().setType(ElementDefinition.DiscriminatorType.TYPE).setPath("$this"); + e.getSlicing().setRules(ElementDefinition.SlicingRules.CLOSED); // type slicing is always closed; the differential might call it open, but that just means it's not constraining the slices it doesn't mention + e.getSlicing().setOrdered(false); + start++; + + String fixedType = null; + List baseSlices = profileUtilities.findBaseSlices(cursors.base, newBaseLimit); + // now process the siblings, which should each be type constrained - and may also have their own children. they may match existing slices + // now we process the base scope repeatedly for each instance of the item in the differential list + for (int i = start; i < diffMatches.size(); i++) { + String type = profileUtilities.determineFixedType(diffMatches, fixedType, i); + // our processing scope for the differential is the item in the list, and all the items before the next one in the list + if (diffMatches.get(i).getMin() > 0) { + if (diffMatches.size() > i + 1) { + throw new FHIRException(profileUtilities.getContext().formatMessage(I18nConstants.INVALID_SLICING__THERE_IS_MORE_THAN_ONE_TYPE_SLICE_AT__BUT_ONE_OF_THEM__HAS_MIN__1_SO_THE_OTHER_SLICES_CANNOT_EXIST, diffMatches.get(i).getPath(), diffMatches.get(i).getSliceName())); + } + fixedType = type; + } + newDiffCursor = getDifferential().getElement().indexOf(diffMatches.get(i)); + newDiffLimit = profileUtilities.findEndOfElement(getDifferential(), newDiffCursor); + int sStart = cursors.baseCursor; + int sEnd = newBaseLimit; + BaseTypeSlice bs = profileUtilities.chooseMatchingBaseSlice(baseSlices, type); + if (bs != null) { + sStart = bs.getStart(); + sEnd = bs.getEnd(); + bs.setHandled(true); + } + + this + .incrementDebugIndent() + .withBaseLimit(sEnd) + .withDiffLimit(newDiffLimit) + .withProfileName(getProfileName() + profileUtilities.pathTail(diffMatches, i)) + .withSlicing(new PathSlicingParams(true, e, currentBasePath)).processPaths( + new ProfilePathProcessorState(cursors.base, sStart, newDiffCursor, cursors.contextName, cursors.resultPathBase)); + } + if (elementToRemove != null) { + getDifferential().getElement().remove(elementToRemove); + newDiffLimit--; + } + if (fixedType != null) { + for (Iterator iter = e.getType().iterator(); iter.hasNext(); ) { + ElementDefinition.TypeRefComponent tr = iter.next(); + if (!tr.getCode().equals(fixedType)) { + iter.remove(); + } + } + } + for (BaseTypeSlice bs : baseSlices) { + if (!bs.isHandled()) { + // ok we gimme up a fake differential that says nothing, and run that against the slice. + StructureDefinition.StructureDefinitionDifferentialComponent fakeDiff = new StructureDefinition.StructureDefinitionDifferentialComponent(); + fakeDiff.getElementFirstRep().setPath(bs.getDefn().getPath()); + + this + .incrementDebugIndent() + .withDifferential(fakeDiff) + .withBaseLimit(bs.getEnd()) + .withDiffLimit(0) + .withProfileName(getProfileName() + profileUtilities.tail(bs.getDefn().getPath())).withSlicing(new PathSlicingParams(true, e, currentBasePath)).processPaths( + new ProfilePathProcessorState(cursors.base, bs.getStart(), 0, cursors.contextName, cursors.resultPathBase)); + + } + } + // ok, done with that - next in the base list + cursors.baseCursor = baseSlices.get(baseSlices.size() - 1).getEnd() + 1; + cursors.diffCursor = newDiffLimit + 1; + //throw new Error("not done yet - slicing / types @ "+cpath); + } + + private void processPathWithSlicedBaseAndEmptyDiffMatches(ElementDefinition currentBase, String currentBasePath, List diffMatches, ProfilePathProcessorState cursors, String path) { + if (profileUtilities.hasInnerDiffMatches(getDifferential(), path, cursors.diffCursor, getDiffLimit(), cursors.base.getElement(), true)) { + // so we just copy it in + ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy()); + outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource())); + profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl()); + profileUtilities.markDerived(outcome); + if (cursors.resultPathBase == null) + cursors.resultPathBase = outcome.getPath(); + else if (!outcome.getPath().startsWith(cursors.resultPathBase)) + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH)); + getResult().getElement().add(outcome); + // the profile walks into this, so we need to as well + // did we implicitly step into a new type? + if (profileUtilities.baseHasChildren(cursors.base, currentBase)) { // not a new type here + + this + .incrementDebugIndent() + .withSlicing(new PathSlicingParams()).processPaths( + new ProfilePathProcessorState(cursors.base, cursors.baseCursor + 1, cursors.diffCursor, cursors.contextName, cursors.resultPathBase)); + cursors.baseCursor = profileUtilities.indexOfFirstNonChild(cursors.base, currentBase, cursors.baseCursor, getBaseLimit()); + } else { + StructureDefinition dt = profileUtilities.getTypeForElement(getDifferential(), cursors.diffCursor, getProfileName(), diffMatches, outcome, getWebUrl(), getDerived()); + cursors.contextName = dt.getUrl(); + int start = cursors.diffCursor; + if (getDifferential().getElement().get(cursors.diffCursor).getPath().equals(currentBasePath)) { + cursors.diffCursor++; + } + while (getDifferential().getElement().size() > cursors.diffCursor && profileUtilities.pathStartsWith(getDifferential().getElement().get(cursors.diffCursor).getPath(), currentBasePath + ".")) { + cursors.diffCursor++; + } + if (cursors.diffCursor > start) { + + this + .incrementDebugIndent() + .withBaseLimit(dt.getSnapshot().getElement().size() - 1) + .withDiffLimit(cursors.diffCursor - 1) + .withWebUrl( profileUtilities.getWebUrl(dt, getWebUrl())) + .withContextPathSource(currentBasePath) + .withContextPathTarget(outcome.getPath()).withSlicing(new PathSlicingParams()).processPaths( /* starting again on the data type, but skip the root */ + new ProfilePathProcessorState(dt.getSnapshot(), 1 /* starting again on the data type, but skip the root */, start, + cursors.contextName, cursors.resultPathBase)); + } + } + cursors.baseCursor++; + } + else { + // the differential doesn't say anything about this item + // copy across the currentbase, and all of its children and siblings + while (cursors.baseCursor < cursors.base.getElement().size() && cursors.base.getElement().get(cursors.baseCursor).getPath().startsWith(path)) { + ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), cursors.base.getElement().get(cursors.baseCursor).copy()); + outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource())); + if (!outcome.getPath().startsWith(cursors.resultPathBase)) + throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH_IN_PROFILE___VS_, getProfileName(), outcome.getPath(), cursors.resultPathBase)); + getResult().getElement().add(outcome); // so we just copy it in + outcome.setUserData(profileUtilities.BASE_MODEL, getSourceStructureDefinition().getUrl()); + outcome.setUserData(profileUtilities.BASE_PATH, cursors.resultPathBase); + cursors.baseCursor++; + } + } + } + + private boolean oneMatchingElementInDifferential(boolean slicingDone, String path, List diffMatches) { + if (diffMatches.size() != 1) { + return false; + } + if (slicingDone) { + return true; + } + if (profileUtilities.isImplicitSlicing(diffMatches.get(0), path)) { + return false; + } + return !(diffMatches.get(0).hasSlicing() + || (profileUtilities.isExtension(diffMatches.get(0)) + && diffMatches.get(0).hasSliceName())); + } + + +} diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessorState.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessorState.java new file mode 100644 index 000000000..fb3cd43d6 --- /dev/null +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessorState.java @@ -0,0 +1,17 @@ +package org.hl7.fhir.r5.conformance.profile; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import org.hl7.fhir.r5.model.StructureDefinition; + +@AllArgsConstructor(access = AccessLevel.PROTECTED) +public class ProfilePathProcessorState { + protected StructureDefinition.StructureDefinitionSnapshotComponent base; + + protected int baseCursor; + protected int diffCursor; + + protected String contextName; + protected String resultPathBase; + +} diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java similarity index 99% rename from org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java rename to org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java index 151a12ad5..7f2b34d3c 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.r5.conformance; +package org.hl7.fhir.r5.conformance.profile; /* Copyright (c) 2011+, HL7, Inc. @@ -48,7 +48,9 @@ import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; -import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider.BindingResolution; +import org.hl7.fhir.r5.conformance.AdditionalBindingsRenderer; +import org.hl7.fhir.r5.conformance.ElementRedirection; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ProfileKnowledgeProvider.BindingResolution; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult; import org.hl7.fhir.r5.elementmodel.ObjectConverter; @@ -638,7 +640,8 @@ public class ProfileUtilities extends TranslatingUtilities { // we actually delegate the work to a subroutine so we can re-enter it with a different cursors StructureDefinitionDifferentialComponent diff = cloneDiff(derived.getDifferential()); // we make a copy here because we're sometimes going to hack the differential while processing it. Have to migrate user data back afterwards - StructureDefinitionSnapshotComponent baseSnapshot = base.getSnapshot(); + + StructureDefinitionSnapshotComponent baseSnapshot = base.getSnapshot(); if (derived.getDerivation() == TypeDerivationRule.SPECIALIZATION) { String derivedType = derived.getTypeName(); @@ -648,7 +651,7 @@ public class ProfileUtilities extends TranslatingUtilities { // debug = true; // } - new ProfilePathProcessor(this).processPaths(base, derived, url, webUrl, diff, baseSnapshot); + ProfilePathProcessor.processPaths(this, base, derived, url, webUrl, diff, baseSnapshot); checkGroupConstraints(derived); if (derived.getDerivation() == TypeDerivationRule.SPECIALIZATION) { @@ -1297,7 +1300,7 @@ public class ProfileUtilities extends TranslatingUtilities { } - protected String getWebUrl(StructureDefinition dt, String webUrl, String indent) { + protected String getWebUrl(StructureDefinition dt, String webUrl) { if (dt.hasUserData("path")) { // this is a hack, but it works for now, since we don't have deep folders String url = dt.getUserString("path"); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/TypeSlice.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/TypeSlice.java similarity index 89% rename from org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/TypeSlice.java rename to org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/TypeSlice.java index fd26ade68..5ac959427 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/TypeSlice.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/TypeSlice.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.r5.conformance; +package org.hl7.fhir.r5.conformance.profile; import org.hl7.fhir.r5.model.ElementDefinition; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java index 10dc87ebb..11349f577 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java @@ -52,10 +52,9 @@ import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.NoTerminologyServiceException; import org.hl7.fhir.exceptions.TerminologyServiceException; -import org.hl7.fhir.r5.conformance.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy; import org.hl7.fhir.r5.context.IWorkerContext.ILoggingService.LogCategory; -import org.hl7.fhir.r5.context.IWorkerContextManager.IPackageLoadingTracker; import org.hl7.fhir.r5.context.TerminologyCache.CacheToken; import org.hl7.fhir.r5.model.ActorDefinition; import org.hl7.fhir.r5.model.BooleanType; @@ -66,7 +65,6 @@ import org.hl7.fhir.r5.model.CapabilityStatement; import org.hl7.fhir.r5.model.CodeSystem; import org.hl7.fhir.r5.model.CodeSystem.CodeSystemContentMode; import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent; -import org.hl7.fhir.r5.model.CodeSystem.ConceptPropertyComponent; import org.hl7.fhir.r5.model.CodeableConcept; import org.hl7.fhir.r5.model.Coding; import org.hl7.fhir.r5.model.ConceptMap; @@ -75,7 +73,6 @@ import org.hl7.fhir.r5.model.DomainResource; import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent; import org.hl7.fhir.r5.model.Enumerations.PublicationStatus; -import org.hl7.fhir.r5.model.Identifier; import org.hl7.fhir.r5.model.ImplementationGuide; import org.hl7.fhir.r5.model.Library; import org.hl7.fhir.r5.model.Measure; @@ -90,13 +87,11 @@ import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent; import org.hl7.fhir.r5.model.PlanDefinition; import org.hl7.fhir.r5.model.PrimitiveType; import org.hl7.fhir.r5.model.Questionnaire; -import org.hl7.fhir.r5.model.Reference; import org.hl7.fhir.r5.model.Requirements; import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.SearchParameter; import org.hl7.fhir.r5.model.StringType; import org.hl7.fhir.r5.model.StructureDefinition; -import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule; import org.hl7.fhir.r5.model.StructureMap; import org.hl7.fhir.r5.model.TerminologyCapabilities; @@ -120,7 +115,6 @@ import org.hl7.fhir.r5.utils.PackageHackerR5; import org.hl7.fhir.r5.utils.ResourceUtilities; import org.hl7.fhir.r5.utils.ToolingExtensions; import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier; -import org.hl7.fhir.utilities.OIDUtils; import org.hl7.fhir.utilities.TimeTracker; import org.hl7.fhir.utilities.ToolingClientLogger; import org.hl7.fhir.utilities.TranslationServices; @@ -128,7 +122,6 @@ import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.i18n.I18nBase; import org.hl7.fhir.utilities.i18n.I18nConstants; -import org.hl7.fhir.utilities.npm.PackageHacker; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationOptions; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/ContextUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/ContextUtilities.java index b1b7815b2..c338d15a9 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/ContextUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/ContextUtilities.java @@ -10,8 +10,8 @@ import java.util.Set; import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.r5.conformance.ProfileUtilities; -import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ProfileKnowledgeProvider; import org.hl7.fhir.r5.model.CanonicalResource; import org.hl7.fhir.r5.model.CodeSystem; import org.hl7.fhir.r5.model.ElementDefinition; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java index c29d917b3..f95ee6263 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java @@ -37,11 +37,9 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -52,22 +50,17 @@ import org.apache.commons.io.IOUtils; import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; -import org.hl7.fhir.r5.conformance.ProfileUtilities; -import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider; import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy; import org.hl7.fhir.r5.context.IWorkerContext.ILoggingService.LogCategory; import org.hl7.fhir.r5.formats.IParser; import org.hl7.fhir.r5.formats.JsonParser; -import org.hl7.fhir.r5.formats.ParserType; import org.hl7.fhir.r5.formats.XmlParser; import org.hl7.fhir.r5.model.*; import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent; -import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent; import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule; import org.hl7.fhir.r5.model.StructureMap.StructureMapModelMode; import org.hl7.fhir.r5.model.StructureMap.StructureMapStructureComponent; -import org.hl7.fhir.r5.terminologies.CodeSystemUtilities; import org.hl7.fhir.r5.terminologies.JurisdictionUtilities; import org.hl7.fhir.r5.terminologies.TerminologyClient; import org.hl7.fhir.r5.utils.validation.IResourceValidator; @@ -82,9 +75,6 @@ import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.npm.BasePackageCacheManager; import org.hl7.fhir.utilities.npm.NpmPackage; import org.hl7.fhir.utilities.npm.NpmPackage.PackageResourceInformation; -import org.hl7.fhir.utilities.validation.ValidationMessage; -import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; -import org.hl7.fhir.utilities.validation.ValidationMessage.Source; import ca.uhn.fhir.parser.DataFormatException; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Element.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Element.java index 01556882a..dfb1fe5f4 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Element.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Element.java @@ -2,34 +2,34 @@ package org.hl7.fhir.r5.elementmodel; import java.io.PrintStream; -/* - 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. - - */ +/* + 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; @@ -43,7 +43,7 @@ import java.util.Set; import org.apache.commons.lang3.Validate; import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.r5.conformance.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.context.ContextUtilities; import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.model.DataType; @@ -55,7 +55,6 @@ import org.hl7.fhir.r5.model.StringType; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; import org.hl7.fhir.r5.model.TypeConvertor; -import org.hl7.fhir.r5.model.Base.ValidationInfo; import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent; import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome; import org.hl7.fhir.utilities.ElementDecoration; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java index 8ce07f498..ad0752524 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java @@ -1,33 +1,33 @@ package org.hl7.fhir.r5.elementmodel; -/* - 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. - - */ +/* + 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. + + */ @@ -39,7 +39,6 @@ import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; -import java.util.IdentityHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -47,7 +46,7 @@ import java.util.Set; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; -import org.hl7.fhir.r5.conformance.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.context.ContextUtilities; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.elementmodel.Element.SpecialElement; @@ -55,13 +54,9 @@ import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.formats.JsonCreator; import org.hl7.fhir.r5.formats.JsonCreatorCanonical; import org.hl7.fhir.r5.formats.JsonCreatorDirect; -import org.hl7.fhir.r5.formats.JsonCreatorGson; -import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; -import org.hl7.fhir.r5.model.Extension; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.utils.FHIRPathEngine; -import org.hl7.fhir.r5.utils.ToolingExtensions; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.StringPair; import org.hl7.fhir.utilities.TextFile; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ObjectConverter.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ObjectConverter.java index 18606b90a..357b12f4e 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ObjectConverter.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ObjectConverter.java @@ -1,33 +1,33 @@ package org.hl7.fhir.r5.elementmodel; -/* - 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. - - */ +/* + 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.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -36,8 +36,8 @@ import java.util.ArrayList; import java.util.List; import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.r5.conformance.ProfileUtilities; -import org.hl7.fhir.r5.conformance.ProfileUtilities.SourcedChildDefinitions; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.SourcedChildDefinitions; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.elementmodel.ParserBase.NamedElement; import org.hl7.fhir.r5.formats.IParser.OutputStyle; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Property.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Property.java index 10ca6681a..de21bff77 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Property.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Property.java @@ -1,45 +1,43 @@ package org.hl7.fhir.r5.elementmodel; -/* - 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. - - */ +/* + 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.List; -import java.util.Map; import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.r5.conformance.ProfileUtilities; -import org.hl7.fhir.r5.conformance.ProfileUtilities.SourcedChildDefinitions; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.SourcedChildDefinitions; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.formats.FormatUtilities; import org.hl7.fhir.r5.model.ElementDefinition; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ResourceParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ResourceParser.java index c0bb77597..482849fe9 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ResourceParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ResourceParser.java @@ -3,36 +3,22 @@ package org.hl7.fhir.r5.elementmodel; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.HashSet; import java.util.List; -import java.util.Set; -import java.util.Map.Entry; import org.apache.commons.lang3.NotImplementedException; import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; -import org.hl7.fhir.r5.conformance.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.elementmodel.Element.SpecialElement; -import org.hl7.fhir.r5.elementmodel.ParserBase.NamedElement; -import org.hl7.fhir.r5.elementmodel.ParserBase.ValidationPolicy; import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.i18n.I18nConstants; -import org.hl7.fhir.utilities.json.JsonTrackingParser; -import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; -import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.xhtml.XhtmlComposer; -import org.hl7.fhir.utilities.xhtml.XhtmlParser; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; public class ResourceParser extends ParserBase { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java index d431b6fc4..57f47aa57 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java @@ -50,10 +50,9 @@ import javax.xml.transform.sax.SAXSource; import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; -import org.hl7.fhir.r5.conformance.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.elementmodel.Element.SpecialElement; -import org.hl7.fhir.r5.elementmodel.ParserBase.ValidationPolicy; import org.hl7.fhir.r5.formats.FormatUtilities; import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.model.DateTimeType; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ElementWrappers.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ElementWrappers.java index 69b4bd567..e44572dd8 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ElementWrappers.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ElementWrappers.java @@ -7,10 +7,8 @@ import java.util.ArrayList; import java.util.List; import org.apache.commons.io.output.ByteArrayOutputStream; -import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; -import org.hl7.fhir.r5.conformance.ProfileUtilities.ElementDefinitionResolution; import org.hl7.fhir.r5.elementmodel.Element; import org.hl7.fhir.r5.elementmodel.XmlParser; import org.hl7.fhir.r5.formats.IParser.OutputStyle; @@ -21,7 +19,6 @@ import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.Narrative.NarrativeStatus; import org.hl7.fhir.r5.model.StringType; import org.hl7.fhir.r5.model.StructureDefinition; -import org.hl7.fhir.r5.renderers.ResourceRenderer; import org.hl7.fhir.r5.renderers.utils.BaseWrappers.BaseWrapper; import org.hl7.fhir.r5.renderers.utils.BaseWrappers.PropertyWrapper; import org.hl7.fhir.r5.renderers.utils.BaseWrappers.RendererWrapperImpl; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/RenderingContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/RenderingContext.java index d425638a4..864a7d4fa 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/RenderingContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/RenderingContext.java @@ -1,28 +1,23 @@ package org.hl7.fhir.r5.renderers.utils; import java.io.IOException; -import java.text.DateFormat; import java.time.ZoneId; import java.time.format.DateTimeFormatter; -import java.time.format.FormatStyle; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.TimeZone; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; -import org.hl7.fhir.r5.conformance.ProfileUtilities; -import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ProfileKnowledgeProvider; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.elementmodel.Element; import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.model.DomainResource; -import org.hl7.fhir.r5.model.Enumerations.FHIRVersion; import org.hl7.fhir.r5.renderers.utils.Resolver.IReferenceResolver; -import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext; import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext; import org.hl7.fhir.utilities.FhirPublication; import org.hl7.fhir.utilities.MarkDownProcessor; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java index 4615d3348..d753d1fb2 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java @@ -22,8 +22,8 @@ import org.fhir.ucum.UcumException; import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.PathEngineException; -import org.hl7.fhir.r5.conformance.ProfileUtilities; -import org.hl7.fhir.r5.conformance.ProfileUtilities.SourcedChildDefinitions; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.SourcedChildDefinitions; import org.hl7.fhir.r5.context.ContextUtilities; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/GraphQLSchemaGenerator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/GraphQLSchemaGenerator.java index bd2bf1854..921f9ff89 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/GraphQLSchemaGenerator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/GraphQLSchemaGenerator.java @@ -35,7 +35,7 @@ package org.hl7.fhir.r5.utils; // - generate inherited search parameters import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.r5.conformance.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.context.ContextUtilities; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.model.ElementDefinition; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/QuestionnaireBuilder.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/QuestionnaireBuilder.java index 15c153c45..289f03852 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/QuestionnaireBuilder.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/QuestionnaireBuilder.java @@ -14,7 +14,7 @@ import org.apache.commons.lang3.NotImplementedException; import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; -import org.hl7.fhir.r5.conformance.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.model.BooleanType; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/StructureMapUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/StructureMapUtilities.java index e8bbca33c..13b634924 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/StructureMapUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/StructureMapUtilities.java @@ -36,8 +36,8 @@ package org.hl7.fhir.r5.utils.structuremap; import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; -import org.hl7.fhir.r5.conformance.ProfileUtilities; -import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ProfileKnowledgeProvider; import org.hl7.fhir.r5.context.ContextUtilities; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult; diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/DiffUtils.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/DiffUtils.java new file mode 100644 index 000000000..2b09541ea --- /dev/null +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/DiffUtils.java @@ -0,0 +1,27 @@ +package org.hl7.fhir.r5; + +import com.github.difflib.patch.AbstractDelta; +import com.github.difflib.patch.Patch; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.List; + +public class DiffUtils { + + public static void testDiff(String expectedPath, String actualPath) throws IOException { + //build simple lists of the lines of the two testfiles + List expected = Files.readAllLines(new File(expectedPath).toPath()); + List actual = Files.readAllLines(new File(actualPath).toPath()); + +//compute the patch: this is the diffutils part + Patch patch = com.github.difflib.DiffUtils.diff(expected, actual); + +//simple output the computed patch to console + for (AbstractDelta delta : patch.getDeltas()) { + System.out.println(delta); + } + } +} diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/NarrativeGenerationTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/NarrativeGenerationTests.java index 8e3157705..a6db55281 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/NarrativeGenerationTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/NarrativeGenerationTests.java @@ -11,8 +11,8 @@ import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.lang3.NotImplementedException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; -import org.hl7.fhir.r5.conformance.ProfileUtilities; -import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ProfileKnowledgeProvider; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.elementmodel.Manager; import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat; @@ -28,7 +28,6 @@ import org.hl7.fhir.r5.renderers.utils.RenderingContext; import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules; import org.hl7.fhir.r5.renderers.utils.RenderingContext.ITypeParser; import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode; -import org.hl7.fhir.r5.test.NarrativeGenerationTests.TestProfileKnowledgeProvider; import org.hl7.fhir.r5.test.utils.CompareUtilities; import org.hl7.fhir.r5.test.utils.TestingUtilities; import org.hl7.fhir.utilities.TerminologyServiceOptions; diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ProfileUtilitiesTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ProfileUtilitiesTests.java index c7e650f8e..e1b9987ad 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ProfileUtilitiesTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ProfileUtilitiesTests.java @@ -4,7 +4,7 @@ import java.util.ArrayList; import java.util.List; import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.r5.conformance.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionConstraintComponent; diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ShexGeneratorTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ShexGeneratorTests.java index 26a3b3408..78cf1b8ca 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ShexGeneratorTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ShexGeneratorTests.java @@ -7,7 +7,7 @@ import java.nio.file.Path; import org.fhir.ucum.UcumException; import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.r5.conformance.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.conformance.ShExGenerator; import org.hl7.fhir.r5.conformance.ShExGenerator.HTMLLinkPolicy; import org.hl7.fhir.r5.model.StructureDefinition; diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java index 963a6cb0e..3d4e6fc84 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java @@ -16,8 +16,9 @@ import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.exceptions.PathEngineException; -import org.hl7.fhir.r5.conformance.ProfileUtilities; -import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider; +import org.hl7.fhir.r5.DiffUtils; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ProfileKnowledgeProvider; import org.hl7.fhir.r5.test.utils.TestPackageLoader; import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.formats.JsonParser; @@ -565,7 +566,13 @@ public class SnapShotGenerationTests { t1.setText(null); StructureDefinition t2 = test.output.copy(); t2.setText(null); - Assertions.assertTrue(t1.equalsDeep(t2), "Output does not match expected"); + + boolean structureDefinitionEquality = t1.equalsDeep(t2); + if (!structureDefinitionEquality) { + System.out.println("Encountered unexpected diff in structure definition"); + DiffUtils.testDiff(dst.getAbsolutePath(), actualFilePath); + } + Assertions.assertTrue(structureDefinitionEquality, "Output does not match expected"); } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java index cf234d386..64e71a771 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java @@ -26,7 +26,7 @@ import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50; import org.hl7.fhir.convertors.txClient.TerminologyClientFactory; import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.r5.conformance.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.context.ContextUtilities; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.context.IWorkerContextManager; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java index e35e261b2..33816e8fc 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java @@ -61,8 +61,8 @@ import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.PathEngineException; import org.hl7.fhir.exceptions.TerminologyServiceException; -import org.hl7.fhir.r5.conformance.ProfileUtilities; -import org.hl7.fhir.r5.conformance.ProfileUtilities.SourcedChildDefinitions; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.SourcedChildDefinitions; import org.hl7.fhir.r5.context.ContextUtilities; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java index 528c12ed5..aba0189a2 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java @@ -13,7 +13,7 @@ import org.hl7.fhir.convertors.factory.VersionConvertorFactory_14_50; import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_50; import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50; import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.r5.conformance.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult; import org.hl7.fhir.r5.elementmodel.Element; diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/comparison/tests/ComparisonTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/comparison/tests/ComparisonTests.java index 58ab30094..d57122f89 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/comparison/tests/ComparisonTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/comparison/tests/ComparisonTests.java @@ -32,7 +32,7 @@ import org.hl7.fhir.r5.comparison.ProfileComparer; import org.hl7.fhir.r5.comparison.ProfileComparer.ProfileComparison; import org.hl7.fhir.r5.comparison.ValueSetComparer; import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison; -import org.hl7.fhir.r5.conformance.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.context.BaseWorkerContext; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.formats.IParser.OutputStyle; diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/SnapShotGenerationXTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/SnapShotGenerationXTests.java index 0bb272980..c710dbb3c 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/SnapShotGenerationXTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/SnapShotGenerationXTests.java @@ -16,8 +16,8 @@ import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.exceptions.PathEngineException; -import org.hl7.fhir.r5.conformance.ProfileUtilities; -import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ProfileKnowledgeProvider; import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.formats.XmlParser; import org.hl7.fhir.r5.model.Base; diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java index e83cc760b..f148b959c 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java @@ -8,7 +8,6 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.io.PrintStream; import java.net.MalformedURLException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -33,10 +32,9 @@ import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.exceptions.PathEngineException; -import org.hl7.fhir.r5.conformance.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.context.ContextUtilities; import org.hl7.fhir.r5.context.IWorkerContext; -import org.hl7.fhir.r5.context.SimpleWorkerContext; import org.hl7.fhir.r5.elementmodel.Element; import org.hl7.fhir.r5.elementmodel.Manager; import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat; @@ -72,7 +70,6 @@ import org.hl7.fhir.utilities.json.JsonTrackingParser; import org.hl7.fhir.utilities.json.JsonUtilities; import org.hl7.fhir.utilities.npm.NpmPackage; import org.hl7.fhir.utilities.validation.ValidationMessage; -import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.validation.IgLoader; import org.hl7.fhir.validation.ValidationEngine; import org.hl7.fhir.validation.cli.model.HtmlInMarkdownCheck; @@ -88,7 +85,6 @@ import org.junit.runners.Parameterized.Parameters; import com.google.common.base.Charsets; import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject;