Merge pull request #1446 from hapifhir/2023-09-gg-pe-r4

Get PE Mode compiling in R4
This commit is contained in:
Grahame Grieve 2023-09-27 22:21:51 +10:00 committed by GitHub
commit 12bc62dee2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 2742 additions and 0 deletions

View File

@ -5269,4 +5269,30 @@ public class ProfileUtilities extends TranslatingUtilities {
this.debug = debug;
}
public static boolean isExtensionDefinition(StructureDefinition sd) {
return sd.getDerivation() == TypeDerivationRule.CONSTRAINT && sd.getType().equals("Extension");
}
public static boolean isSimpleExtension(StructureDefinition sd) {
if (!isExtensionDefinition(sd)) {
return false;
}
ElementDefinition value = sd.getSnapshot().getElementByPath("Extension.value");
return value != null && !value.isProhibited();
}
public static boolean isComplexExtension(StructureDefinition sd) {
if (!isExtensionDefinition(sd)) {
return false;
}
ElementDefinition value = sd.getSnapshot().getElementByPath("Extension.value");
return value == null || value.isProhibited();
}
public static boolean isModifierExtension(StructureDefinition sd) {
ElementDefinition defn = sd.getSnapshot().getElementByPath("Extension");
return defn.getIsModifier();
}
}

View File

@ -889,6 +889,14 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
}
}
public <T extends Resource> T fetchResource(Class<T> class_, String uri, String version) {
try {
return fetchResourceWithException(class_, uri+"|"+version);
} catch (FHIRException e) {
throw new Error(e);
}
}
@Override
public <T extends Resource> boolean hasResource(Class<T> class_, String uri) {
try {
@ -1148,6 +1156,17 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
return fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + typeName);
}
public boolean isPrimitiveType(String type) {
return Utilities.existsInList(type, "boolean", "integer", "integer64", "string", "decimal", "uri", "base64Binary", "instant", "date", "dateTime", "time", "code", "oid", "id", "markdown", "unsignedInt", "positiveInt", "uuid", "xhtml", "url", "canonical");
}
public boolean isDataType(String type) {
return Utilities.existsInList(type, "Address", "Age", "Annotation", "Attachment", "CodeableConcept", "Coding", "ContactPoint", "Count", "Distance", "Duration", "HumanName", "Identifier", "Money", "Period", "Quantity", "Range", "Ratio", "Reference", "SampledData", "Signature", "Timing",
"ContactDetail", "Contributor", "DataRequirement", "Expression", "ParameterDefinition", "RelatedArtifact", "TriggerDefinition", "UsageContext");
}
public boolean isTlogging() {
return tlogging;
}

View File

@ -168,6 +168,7 @@ public interface IWorkerContext {
* @throws Exception
*/
public <T extends Resource> T fetchResource(Class<T> class_, String uri);
public <T extends Resource> T fetchResource(Class<T> class_, String uri, String version);
public <T extends Resource> T fetchResourceWithException(Class<T> class_, String uri) throws FHIRException;
@ -488,4 +489,6 @@ public interface IWorkerContext {
public void setUcumService(UcumService ucumService);
public String getLinkForUrl(String corePath, String s);
public boolean isPrimitiveType(String code);
}

View File

@ -9692,6 +9692,42 @@ public class ElementDefinition extends BackboneType implements ICompositeType {
return hasFixed() ? getFixed() : getPattern();
}
public String getName() {
return hasPath() ? getPath().contains(".") ? getPath().substring(getPath().lastIndexOf(".")+1) : getPath() : null;
}
public boolean getMustHaveValue() {
return false;
}
public boolean isChoice() {
return getPath().endsWith("[x]");
}
public String getNameBase() {
return getName().replace("[x]", "");
}
public boolean unbounded() {
return getMax().equals("*") || Integer.parseInt(getMax()) > 1;
}
public boolean isMandatory() {
return getMin() > 0;
}
public boolean prohibited() {
return "0".equals(getMax());
}
public boolean isProhibited() {
return "0".equals(getMax());
}
public boolean isRequired() {
return getMin() == 1;
}
// end addition
}

View File

@ -1475,6 +1475,31 @@ public class StructureDefinition extends MetadataResource {
}
public ElementDefinition getElementByPath(String path) {
if (path == null) {
return null;
}
for (ElementDefinition ed : getElement()) {
if (path.equals(ed.getPath()) || (path+"[x]").equals(ed.getPath())) {
return ed;
}
}
return null;
}
public ElementDefinition getElementById(String id) {
if (id == null) {
return null;
}
for (ElementDefinition ed : getElement()) {
if (id.equals(ed.getId())) {
return ed;
}
}
return null;
}
}
@Block()
@ -4804,4 +4829,8 @@ public class StructureDefinition extends MetadataResource {
public static final ca.uhn.fhir.model.api.Include INCLUDE_BASE = new ca.uhn.fhir.model.api.Include(
"StructureDefinition:base").toLocked();
public String getVersionedUrl() {
return hasVersion() ? getUrl()+"|"+getVersion() : getUrl();
}
}

View File

@ -0,0 +1,613 @@
package org.hl7.fhir.r4.profilemodel;
/*
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.List;
import org.apache.commons.lang3.NotImplementedException;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.r4.conformance.ProfileUtilities;
import org.hl7.fhir.r4.context.IWorkerContext;
import org.hl7.fhir.r4.model.Base;
import org.hl7.fhir.r4.model.CanonicalType;
import org.hl7.fhir.r4.model.ElementDefinition;
import org.hl7.fhir.r4.model.ElementDefinition.DiscriminatorType;
import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionSlicingComponent;
import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionSlicingDiscriminatorComponent;
import org.hl7.fhir.r4.model.ElementDefinition.SlicingRules;
import org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r4.model.Resource;
import org.hl7.fhir.r4.model.ResourceFactory;
import org.hl7.fhir.r4.model.StructureDefinition;
import org.hl7.fhir.r4.model.StructureDefinition.TypeDerivationRule;
import org.hl7.fhir.r4.utils.FHIRPathEngine;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.Utilities;
/**
* Factory class for the ProfiledElement sub-system
*
* *** NOTE: This sub-system is still under development ***
*
* This subsystem takes a profile and creates a view of the profile that stitches
* all the parts together, and presents it as a seamless tree. There's two views:
*
* - definition: A logical view of the contents of the profile
* - instance: a logical view of a resource that conforms to the profile
*
* The tree of elements in the profile model is different to the the base resource:
* - some elements are removed (max = 0)
* - extensions are turned into named elements
* - slices are turned into named elements
* - element properties - doco, cardinality, binding etc is updated for what the profile says
*
* Definition
* ----------
* This presents a single view of the contents of a resource as specified by
* the profile. It's suitable for use in any kind of tree view.
*
* Each node has a unique name amongst it's siblings, but this name may not be
* the name in the instance, since slicing splits up a single named element into
* different definitions.
*
* Each node has:
* - name (unique amongst siblings)
* - schema name (the actual name in the instance)
* - min cardinality
* - max cardinality
* - short documentation (for the tree view)
* - full documentation (markdown source)
* - profile definition - the full definition in the profile
* - base definition - the full definition at the resource level
* - types() - a list of possible types
* - children(type) - a list of child nodes for the provided type
* - expansion - if there's a binding, the codes in the expansion based on the binding
*
* Note that the tree may not have leaves; the trees recurse indefinitely because
* extensions have extensions etc. So you can't do a depth-first search of the tree
* without some kind of decision to stop at a given point.
*
* Instance
* --------
*
* todo
*
* @author grahamegrieve
*
*/
public class PEBuilder {
public enum PEElementPropertiesPolicy {
NONE, EXTENSION, EXTENSION_ID
}
private IWorkerContext context;
private ProfileUtilities pu;
private PEElementPropertiesPolicy elementProps;
private boolean fixedPropsDefault;
private FHIRPathEngine fpe;
/**
* @param context - must be loaded with R5 definitions
* @param elementProps - whether to include Element.id and Element.extension in the tree. Recommended choice: Extension
*/
public PEBuilder(IWorkerContext context, PEElementPropertiesPolicy elementProps, boolean fixedPropsDefault) {
super();
this.context = context;
this.elementProps = elementProps;
this.fixedPropsDefault = fixedPropsDefault;
pu = new ProfileUtilities(context, null, null);
fpe = new FHIRPathEngine(context, pu);
}
/**
* Given a profile, return a tree of the elements defined in the profile model. This builds the profile model
* for the provided version of the nominated profile
*
* The tree of elements in the profile model is different to those defined in the base resource:
* - some elements are removed (max = 0)
* - extensions are turned into named elements
* - slices are turned into named elements
* - element properties - doco, cardinality, binding etc is updated for what the profile says
*
* Warning: profiles and resources are recursive; you can't iterate this tree until it you get
* to the leaves because there are nodes that don't terminate (extensions have extensions)
*
*/
public PEDefinition buildPEDefinition(StructureDefinition profile) {
if (!profile.hasSnapshot()) {
throw new DefinitionException("Profile '"+profile.getVersionedUrl()+"' does not have a snapshot");
}
return new PEDefinitionResource(this, profile, profile.getName());
}
/**
* Given a profile, return a tree of the elements defined in the profile model. This builds the profile model
* for the latest version of the nominated profile
*
* The tree of elements in the profile model is different to those defined in the base resource:
* - some elements are removed (max = 0)
* - extensions are turned into named elements
* - slices are turned into named elements
* - element properties - doco, cardinality, binding etc is updated for what the profile says
*
* Warning: profiles and resources are recursive; you can't iterate this tree until it you get
* to the leaves because there are nodes that don't terminate (extensions have extensions)
*
*/
public PEDefinition buildPEDefinition(String url) {
StructureDefinition profile = getProfile(url);
if (profile == null) {
throw new DefinitionException("Unable to find profile for URL '"+url+"'");
}
if (!profile.hasSnapshot()) {
throw new DefinitionException("Profile '"+url+"' does not have a snapshot");
}
return new PEDefinitionResource(this, profile, profile.getName());
}
/**
* Given a profile, return a tree of the elements defined in the profile model. This builds the profile model
* for the nominated version of the nominated profile
*
* The tree of elements in the profile model is different to the the base resource:
* - some elements are removed (max = 0)
* - extensions are turned into named elements
* - slices are turned into named elements
* - element properties - doco, cardinality, binding etc is updated for what the profile says
*
* Warning: profiles and resources can be recursive; you can't iterate this tree until it you get
* to the leaves because you will never get to a child that doesn't have children
*
*/
public PEDefinition buildPEDefinition(String url, String version) {
StructureDefinition profile = getProfile(url, version);
if (profile == null) {
throw new DefinitionException("Unable to find profile for URL '"+url+"'");
}
if (!profile.hasSnapshot()) {
throw new DefinitionException("Profile '"+url+"' does not have a snapshot");
}
return new PEDefinitionResource(this, profile, profile.getName());
}
/**
* Given a resource and a profile, return a tree of instance data as defined by the profile model
* using the latest version of the profile
*
* The tree is a facade to the underlying resource - all actual data is stored against the resource,
* and retrieved on the fly from the resource, so that applications can work at either level, as
* convenient.
*
* Note that there's a risk that deleting something through the resource while holding
* a handle to a PEInstance that is a facade on what is deleted leaves an orphan facade
* that will continue to function, but is making changes to resource content that is no
* longer part of the resource
*
*/
public PEInstance buildPEInstance(String url, Resource resource) {
PEDefinition defn = buildPEDefinition(url);
return loadInstance(defn, resource);
}
/**
* Given a resource and a profile, return a tree of instance data as defined by the profile model
* using the provided version of the profile
*
* The tree is a facade to the underlying resource - all actual data is stored against the resource,
* and retrieved on the fly from the resource, so that applications can work at either level, as
* convenient.
*
* Note that there's a risk that deleting something through the resource while holding
* a handle to a PEInstance that is a facade on what is deleted leaves an orphan facade
* that will continue to function, but is making changes to resource content that is no
* longer part of the resource
*
*/
public PEInstance buildPEInstance(StructureDefinition profile, Resource resource) {
PEDefinition defn = buildPEDefinition(profile);
return loadInstance(defn, resource);
}
/**
* Given a resource and a profile, return a tree of instance data as defined by the profile model
* using the nominated version of the profile
*
* The tree is a facade to the underlying resource - all actual data is stored against the resource,
* and retrieved on the fly from the resource, so that applications can work at either level, as
* convenient.
*
* Note that there's a risk that deleting something through the resource while holding
* a handle to a PEInstance that is a facade on what is deleted leaves an orphan facade
* that will continue to function, but is making changes to resource content that is no
* longer part of the resource
*/
public PEInstance buildPEInstance(String url, String version, Resource resource) {
PEDefinition defn = buildPEDefinition(url, version);
return loadInstance(defn, resource);
}
/**
* For the current version of a profile, construct a resource and fill out any fixed or required elements
*
* Note that fixed values are filled out irrespective of the value of fixedProps when the builder is created
*
* @param url identifies the profile
* @param version identifies the version of the profile
* @param meta whether to mark the profile in Resource.meta.profile
* @return constructed resource
*/
public Resource createResource(String url, String version, boolean meta) {
PEDefinition definition = buildPEDefinition(url, version);
Resource res = ResourceFactory.createResource(definition.types().get(0).getType());
populateByProfile(res, definition);
if (meta) {
res.getMeta().addProfile(definition.profile.getUrl());
}
return res;
}
/**
* For the provided version of a profile, construct a resource and fill out any fixed or required elements
*
* Note that fixed values are filled out irrespective of the value of fixedProps when the builder is created
*
* @param profile the profile
* @param meta whether to mark the profile in Resource.meta.profile
* @return constructed resource
*/
public Resource createResource(StructureDefinition profile, boolean meta) {
PEDefinition definition = buildPEDefinition(profile);
Resource res = ResourceFactory.createResource(definition.types().get(0).getType());
populateByProfile(res, definition);
if (meta) {
res.getMeta().addProfile(definition.profile.getUrl());
}
return res;
}
/**
* For the current version of a profile, construct a resource and fill out any fixed or required elements
*
* Note that fixed values are filled out irrespective of the value of fixedProps when the builder is created
*
* @param url identifies the profile
* @param meta whether to mark the profile in Resource.meta.profile
* @return constructed resource
*/
public Resource createResource(String url, boolean meta) {
PEDefinition definition = buildPEDefinition(url);
Resource res = ResourceFactory.createResource(definition.types().get(0).getType());
populateByProfile(res, definition);
if (meta) {
res.getMeta().addProfile(definition.profile.getUrl());
}
return res;
}
// -- methods below here are only used internally to the package
private StructureDefinition getProfile(String url) {
return context.fetchResource(StructureDefinition.class, url);
}
private StructureDefinition getProfile(String url, String version) {
return context.fetchResource(StructureDefinition.class, url, version);
}
//
// protected List<PEDefinition> listChildren(boolean allFixed, StructureDefinition profileStructure, ElementDefinition definition, TypeRefComponent t, CanonicalType u) {
// // TODO Auto-generated method stub
// return null;
// }
protected List<PEDefinition> listChildren(boolean allFixed, PEDefinition parent, StructureDefinition profileStructure, ElementDefinition definition, String url, String... omitList) {
StructureDefinition profile = profileStructure;
List<ElementDefinition> list = pu.getChildList(profile, definition);
if (definition.getType().size() == 1 || (!definition.getPath().contains(".")) || list.isEmpty()) {
assert url == null || checkType(definition, url);
List<PEDefinition> res = new ArrayList<>();
if (list.size() == 0) {
profile = context.fetchResource(StructureDefinition.class, url);
list = pu.getChildList(profile, profile.getSnapshot().getElementFirstRep());
}
if (list.size() > 0) {
int i = 0;
while (i < list.size()) {
ElementDefinition defn = list.get(i);
if (!defn.getMax().equals("0") && (allFixed || include(defn))) {
if (passElementPropsCheck(defn) && !Utilities.existsInList(defn.getName(), omitList)) {
PEDefinitionElement pe = new PEDefinitionElement(this, profile, defn, parent.path());
pe.setRecursing(definition == defn || (profile.getDerivation() == TypeDerivationRule.SPECIALIZATION && profile.getType().equals("Extension")));
if (context.isPrimitiveType(definition.getTypeFirstRep().getWorkingCode()) && "value".equals(pe.name())) {
pe.setMustHaveValue(definition.getMustHaveValue());
}
pe.setInFixedValue(definition.hasFixed() || definition.hasPattern() || parent.isInFixedValue());
if (defn.hasSlicing()) {
if (defn.getSlicing().getRules() != SlicingRules.CLOSED) {
res.add(pe);
pe.setSlicer(true);
}
i++;
while (i < list.size() && list.get(i).getPath().equals(defn.getPath())) {
StructureDefinition ext = getExtensionDefinition(list.get(i));
if (ext != null) {
res.add(new PEDefinitionExtension(this, list.get(i).getSliceName(), profile, list.get(i), defn, ext, parent.path()));
} else if (isTypeSlicing(defn)) {
res.add(new PEDefinitionTypeSlice(this, list.get(i).getSliceName(), profile, list.get(i), defn, parent.path()));
} else {
if (ProfileUtilities.isComplexExtension(profile) && defn.getPath().endsWith(".extension")) {
res.add(new PEDefinitionSubExtension(this, profile, list.get(i), parent.path()));
} else {
res.add(new PEDefinitionSlice(this, list.get(i).getSliceName(), profile, list.get(i), defn, parent.path()));
}
}
i++;
}
} else {
res.add(pe);
i++;
}
} else {
i++;
}
} else {
i++;
}
}
}
return res;
} else if (list.isEmpty()) {
throw new DefinitionException("not done yet!");
} else {
throw new DefinitionException("not done yet");
}
}
protected PEDefinition makeChild(PEDefinition parent, StructureDefinition profileStructure, ElementDefinition definition) {
PEDefinitionElement pe = new PEDefinitionElement(this, profileStructure, definition, parent.path());
if (context.isPrimitiveType(definition.getTypeFirstRep().getWorkingCode()) && "value".equals(pe.name())) {
pe.setMustHaveValue(definition.getMustHaveValue());
}
pe.setInFixedValue(definition.hasFixed() || definition.hasPattern() || parent.isInFixedValue());
return pe;
}
private boolean passElementPropsCheck(ElementDefinition bdefn) {
switch (elementProps) {
case EXTENSION:
return !Utilities.existsInList(bdefn.getBase().getPath(), "Element.id");
case NONE:
return !Utilities.existsInList(bdefn.getBase().getPath(), "Element.id", "Element.extension");
case EXTENSION_ID:
default:
return true;
}
}
private boolean isTypeSlicing(ElementDefinition defn) {
ElementDefinitionSlicingComponent sl = defn.getSlicing();
return sl.getRules() == SlicingRules.CLOSED && sl.getDiscriminator().size() == 1 &&
sl.getDiscriminatorFirstRep().getType() == DiscriminatorType.TYPE && "$this".equals(sl.getDiscriminatorFirstRep().getPath());
}
private boolean include(ElementDefinition defn) {
if (fixedPropsDefault) {
return true;
} else {
return !(defn.hasFixed() || defn.hasPattern());
}
}
protected List<PEDefinition> listSlices(StructureDefinition profileStructure, ElementDefinition definition, PEDefinition parent) {
List<ElementDefinition> list = pu.getSliceList(profileStructure, definition);
List<PEDefinition> res = new ArrayList<>();
for (ElementDefinition ed : list) {
if (profileStructure.getDerivation() == TypeDerivationRule.CONSTRAINT && profileStructure.getType().equals("Extension")) {
res.add(new PEDefinitionSubExtension(this, profileStructure, ed, parent.path()));
} else {
PEDefinitionElement pe = new PEDefinitionElement(this, profileStructure, ed, parent.path());
pe.setRecursing(definition == ed || (profileStructure.getDerivation() == TypeDerivationRule.SPECIALIZATION && profileStructure.getType().equals("Extension")));
res.add(pe);
}
}
return res;
}
private boolean checkType(ElementDefinition defn, String url) {
for (TypeRefComponent t : defn.getType()) {
if (("http://hl7.org/fhir/StructureDefinition/"+t.getWorkingCode()).equals(url)) {
return true;
}
for (CanonicalType u : t.getProfile()) {
if (url.equals(u.getValue())) {
return true;
}
}
}
return !defn.getPath().contains(".");
}
private StructureDefinition getExtensionDefinition(ElementDefinition ed) {
if ("Extension".equals(ed.getTypeFirstRep().getWorkingCode()) && ed.getTypeFirstRep().getProfile().size() == 1) {
return context.fetchResource(StructureDefinition.class, ed.getTypeFirstRep().getProfile().get(0).asStringValue());
} else {
return null;
}
}
private ElementDefinition getByName(List<ElementDefinition> blist, String name) {
for (ElementDefinition ed : blist) {
if (name.equals(ed.getName())) {
return ed;
}
}
return null;
}
protected PEType makeType(TypeRefComponent t) {
if (t.hasProfile()) {
StructureDefinition sd = context.fetchResource(StructureDefinition.class, t.getProfile().get(0).getValue());
if (sd == null) {
return new PEType(tail(t.getProfile().get(0).getValue()), t.getWorkingCode(), t.getProfile().get(0).getValue());
} else {
return new PEType(sd.getName(), t.getWorkingCode(), t.getProfile().get(0).getValue());
}
} else {
return makeType(t.getWorkingCode());
}
}
protected PEType makeType(TypeRefComponent t, CanonicalType u) {
StructureDefinition sd = context.fetchResource(StructureDefinition.class, u.getValue());
if (sd == null) {
return new PEType(tail(u.getValue()), t.getWorkingCode(), u.getValue());
} else {
return new PEType(sd.getName(), t.getWorkingCode(), u.getValue());
}
}
protected PEType makeType(String tn, String url) {
return new PEType(tn, tn, url);
}
protected PEType makeType(String tn) {
return new PEType(tn, tn, "http://hl7.org/fhir/StructureDefinition/"+ tn);
}
private String tail(String value) {
return value.contains("/") ? value.substring(value.lastIndexOf("/")+1) : value;
}
protected List<ElementDefinition> getChildren(StructureDefinition profileStructure, ElementDefinition definition) {
return pu.getChildList(profileStructure, definition);
}
private PEInstance loadInstance(PEDefinition defn, Resource resource) {
return new PEInstance(this, defn, resource, resource, defn.name());
}
public IWorkerContext getContext() {
return context;
}
protected void populateByProfile(Base base, PEDefinition definition) {
if (definition.types().size() == 1) {
for (PEDefinition pe : definition.directChildren(true)) {
if (pe.fixedValue()) {
if (pe.definition().hasPattern()) {
base.setProperty(pe.schemaName(), pe.definition().getPattern());
} else {
base.setProperty(pe.schemaName(), pe.definition().getFixed());
}
} else if (!pe.isSlicer() && pe.max() == 1) {
for (int i = 0; i < pe.min(); i++) {
Base b = null;
if (pe.schemaName().endsWith("[x]")) {
if (pe.types().size() == 1) {
b = base.addChild(pe.schemaName().replace("[x]", Utilities.capitalize(pe.types().get(0).getType())));
}
} else if (!pe.isBaseList()) {
b = base.makeProperty(pe.schemaName().hashCode(), pe.schemaName());
} else {
b = base.addChild(pe.schemaName());
}
if (b != null) {
populateByProfile(b, pe);
}
}
}
}
}
}
public String makeSliceExpression(StructureDefinition profile, ElementDefinitionSlicingComponent slicing, ElementDefinition definition) {
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(" and ");
for (ElementDefinitionSlicingDiscriminatorComponent d : slicing.getDiscriminator()) {
switch (d.getType()) {
case EXISTS:
throw new DefinitionException("The discriminator type 'exists' is not supported by the PEBuilder");
case PATTERN:
throw new DefinitionException("The discriminator type 'pattern' is not supported by the PEBuilder");
case PROFILE:
throw new DefinitionException("The discriminator type 'profile' is not supported by the PEBuilder");
case TYPE:
throw new DefinitionException("The discriminator type 'type' is not supported by the PEBuilder");
case VALUE:
String path = d.getPath();
if (path.contains(".")) {
throw new DefinitionException("The discriminator path '"+path+"' is not supported by the PEBuilder");
}
ElementDefinition ed = getChildElement(profile, definition, path);
if (ed == null) {
throw new DefinitionException("The discriminator path '"+path+"' could not be resolved by the PEBuilder");
}
if (!ed.hasFixed()) {
throw new DefinitionException("The discriminator path '"+path+"' has no fixed value - this is not supported by the PEBuilder");
}
if (!ed.getFixed().isPrimitive()) {
throw new DefinitionException("The discriminator path '"+path+"' has a fixed value that is not a primitive ("+ed.getFixed().fhirType()+") - this is not supported by the PEBuilder");
}
b.append(path+" = '"+ed.getFixed().primitiveValue()+"'");
break;
case NULL:
throw new DefinitionException("The discriminator type 'null' is not supported by the PEBuilder");
default:
throw new DefinitionException("The discriminator type '??' is not supported by the PEBuilder");
}
}
return b.toString();
}
private ElementDefinition getChildElement(StructureDefinition profile, ElementDefinition definition, String path) {
List<ElementDefinition> elements = pu.getChildList(profile, definition);
if (elements.size() == 0) {
profile = definition.getTypeFirstRep().hasProfile() ? context.fetchResource(StructureDefinition.class, definition.getTypeFirstRep().getProfile().get(0).asStringValue()) :
context.fetchTypeDefinition(definition.getTypeFirstRep().getWorkingCode());
elements = pu.getChildList(profile, profile.getSnapshot().getElementFirstRep());
}
return getByName(elements, path);
}
public List<Base> exec(Resource resource, Base data, String fhirpath) {
return fpe.evaluate(this, resource, resource, data, fhirpath);
}
public boolean isResource(String name) {
return context.getResourceNamesAsSet().contains(name);
}
}

View File

@ -0,0 +1,391 @@
package org.hl7.fhir.r4.profilemodel;
/*
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.apache.xmlbeans.impl.xb.xsdschema.All;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.r4.model.Base;
import org.hl7.fhir.r4.model.ElementDefinition;
import org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r4.model.StructureDefinition;
import org.hl7.fhir.r4.profilemodel.PEDefinition.PEDefinitionElementMode;
import org.hl7.fhir.utilities.Utilities;
public abstract class PEDefinition {
public enum PEDefinitionElementMode {
Resource, Element, DataType, Extension
}
protected PEBuilder builder;
protected String name;
protected String path;
protected StructureDefinition profile;
protected ElementDefinition definition;
protected List<PEType> types;
protected Map<String, List<PEDefinition>> children = new HashMap<>();
private boolean recursing;
private boolean mustHaveValue;
private boolean inFixedValue;
private boolean isSlicer;
private List<PEDefinition> slices; // if there are some...
// /**
// * Don't create one of these directly - always use the public methods on ProfiledElementBuilder
// *
// * @param builder
// * @param baseElement
// * @param profiledElement
// * @param data
// */
// protected PEDefinition(PEBuilder builder, String name,
// ElementDefinition definition, Base data) {
// super();
// this.builder = builder;
// this.name = name;
// this.definition = definition;
//// this.data = data;
// }
protected PEDefinition(PEBuilder builder, String name, StructureDefinition profile, ElementDefinition definition, String ppath) {
this.builder = builder;
this.name = name;
this.profile = profile;
this.definition = definition;
this.path = path == null ? name : ppath+"."+name;
}
/**
* @return The name of the element or slice in the profile (always unique amongst children)
*/
public String name() {
return name;
}
/**
* @return The path of the element or slice in the profile (name.name.name...)
*/
public String path() {
return path;
}
/**
* @return The name of the element in the resource (may be different to the slice name)
*/
public String schemaName() {
String n = definition.getName();
return n;
}
/**
* @return The name of the element in the resource (may be different to the slice name)
*/
public String schemaNameWithType() {
String n = definition.getName();
if (n.endsWith("[x]") && types().size() == 1) {
n = n.replace("[x]", Utilities.capitalize(types.get(0).getType()));
}
return n;
}
/**
* @return a list of types. There is usually at least one type; it might be Element, Type, BackboneElement or BackboneType
*
* The following elements don't have types (true primitives): Element.id. Extension.url, PrimitiveType.value
*/
public List<PEType> types() {
if (types == null) {
List<PEType> ltypes = new ArrayList<>();
listTypes(ltypes);
types = ltypes;
}
return types;
}
protected abstract void listTypes(List<PEType> types);
/**
* @return The minimum number of repeats allowed
*/
public int min() {
return mustHaveValue ? 1 : definition.getMin();
}
/**
* @return the maximum number of repeats allowed
*/
public int max() {
return definition.getMax() == null || "*".equals(definition.getMax()) ? Integer.MAX_VALUE : Integer.parseInt(definition.getMax());
}
/**
* @return the definition of the element in the profile (fully populated)
*
* Note that the profile definition might be the same as a base definition, when the tree runs off the end of what's profiled
*/
public ElementDefinition definition() {
return definition;
}
/**
* @return the definition of the element in the base specification
*
* Note that the profile definition might be the same as a base definition, when the tree runs off the end of what's profiled
*/
public ElementDefinition baseDefinition() {
String type = definition.getBase().getPath();
if (type.contains(".")) {
type= type.substring(0, type.indexOf("."));
}
StructureDefinition sd = builder.getContext().fetchTypeDefinition(type);
return sd.getSnapshot().getElementByPath(definition.getBase().getPath());
}
/**
* @return the short documentation of the definition (shown in the profile table view)
*/
public String shortDocumentation() {
return definition.getShort();
}
/**
* @return the full definition of the element (markdown syntax)
*/
public String documentation() {
return definition.getDefinition();
}
// /**
// * @return if the profiled definition has a value set, get the expansion
// */
// public ValueSet expansion() {
// throw new NotImplementedException("Not done yet");
// }
//
/**
* @param typeUrl - the url of one of the types listed in types()
* @return - the list of children for the nominated type
*
* Warning: profiles and resources can be recursive; you can't iterate this tree until you get
* to the leaves because you will never get to a child that doesn't have children (extensions have extensions etc)
*
*/
public List<PEDefinition> children(String typeUrl) {
return children(typeUrl, false);
}
public List<PEDefinition> children(String typeUrl, boolean allFixed) {
if (children.containsKey(typeUrl+"$"+allFixed)) {
return children.get(typeUrl+"$"+allFixed);
}
List<PEDefinition> res = new ArrayList<>();
makeChildren(typeUrl, res, allFixed);
children.put(typeUrl+"$"+allFixed, res);
return res;
}
public List<PEDefinition> children() {
if (types().size() == 1) {
return children(types.get(0).getUrl(), false);
} else {
throw new DefinitionException("Attempt to get children for an element that doesn't have a single type (types = "+types()+")");
}
}
public List<PEDefinition> children(boolean allFixed) {
if (types().size() == 1) {
return children(types.get(0).getUrl(), allFixed);
} else {
throw new DefinitionException("Attempt to get children for an element that doesn't have a single type (types = "+types()+")");
}
}
/**
* @return True if the element has a fixed value. This will always be false if fixedProps = false when the builder is created
*/
public boolean fixedValue() {
return definition.hasFixed() || definition.hasPattern();
}
protected abstract void makeChildren(String typeUrl, List<PEDefinition> children, boolean allFixed);
@Override
public String toString() {
return name+"("+schemaName()+"):"+types().toString()+" ["+min()+":"+(max() == Integer.MAX_VALUE ? "*" : max() )+"] \""+shortDocumentation()+"\"";
}
/**
* @return true if the builder observes that this element is recursing (extensions have extensions)
*
* Note that this is unreliable and may be withdrawn if it can't be fixed
*/
public boolean isRecursing() {
return recursing;
}
protected void setRecursing(boolean recursing) {
this.recursing = recursing;
}
protected boolean isMustHaveValue() {
return mustHaveValue;
}
protected void setMustHaveValue(boolean mustHaveValue) {
this.mustHaveValue = mustHaveValue;
}
/**
* @return true if this property is inside an element that has an assigned fixed value
*/
public boolean isInFixedValue() {
return inFixedValue;
}
protected void setInFixedValue(boolean inFixedValue) {
this.inFixedValue = inFixedValue;
}
/**
* This is public to support unit testing - there's no reason to use it otherwise
*
* @return used in the instance processor to differentiate slices
*/
public abstract String fhirpath();
public boolean isList() {
return "*".equals(definition.getMax());
}
public boolean repeats() {
return max() > 1;
}
public PEDefinitionElementMode mode() {
if (builder.isResource(definition.getBase().getPath())) {
return PEDefinitionElementMode.Resource;
}
for (TypeRefComponent tr : definition.getType()) {
if ("Extension".equals(tr.getWorkingCode())) {
return PEDefinitionElementMode.Extension;
}
if (!Utilities.existsInList(tr.getWorkingCode(), "Element", "BackboneElement")) {
return PEDefinitionElementMode.DataType;
}
}
return PEDefinitionElementMode.Element;
}
/**
* @return true if this element is profiled one way or another
*/
public boolean isProfiled() {
return !profile.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition");
}
public boolean isSlicer() {
return isSlicer;
}
public void setSlicer(boolean isSlicer) {
this.isSlicer = isSlicer;
}
public boolean isBaseList() {
return !"1".equals(definition.getBase().getMax());
}
public StructureDefinition getProfile() {
return profile;
}
public boolean isKeyElement() {
boolean selfKey = definition.getMustSupport() || definition.getMustHaveValue() || min() > 0 || definition.hasCondition();
if (isProfiled() && !selfKey) {
if (types() != null && types().size() > 0) {
for (PEDefinition child : children()) {
if (child.isKeyElement()) {
return true;
}
}
}
}
return selfKey;
}
public boolean isPrimitive() {
return types().size() == 1 && builder.getContext().isPrimitiveType(types.get(0).getName());
}
public boolean isBasePrimitive() {
ElementDefinition ed = baseDefinition();
return ed != null && ed.getType().size() == 1 && builder.getContext().isPrimitiveType(ed.getType().get(0).getWorkingCode());
}
// extensions do something different here
public List<PEDefinition> directChildren(boolean allFixed) {
return children(allFixed);
}
public List<PEDefinition> getSlices() {
return slices;
}
public void setSlices(List<PEDefinition> slices) {
this.slices = slices;
}
public boolean isExtension() {
return false;
}
}

View File

@ -0,0 +1,84 @@
package org.hl7.fhir.r4.profilemodel;
/*
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.List;
import org.hl7.fhir.r4.model.CanonicalType;
import org.hl7.fhir.r4.model.ElementDefinition;
import org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r4.model.StructureDefinition;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
public class PEDefinitionElement extends PEDefinition {
public PEDefinitionElement(PEBuilder builder, StructureDefinition profile, ElementDefinition definition, String ppath) {
super(builder, definition.getName(), profile, definition, ppath);
}
@Override
public void listTypes(List<PEType> types) {
for (TypeRefComponent t : definition.getType()) {
if (t.hasProfile()) {
for (CanonicalType u : t.getProfile()) {
types.add(builder.makeType(t, u));
}
} else if (!t.getCode().startsWith("http://hl7.org/fhirpath/")) {
types.add(new PEType(t.getWorkingCode(), t.getWorkingCode(), "http://hl7.org/fhir/StructureDefinition/"+t.getWorkingCode()));
}
}
}
@Override
protected void makeChildren(String typeUrl, List<PEDefinition> children, boolean allFixed) {
children.addAll(builder.listChildren(allFixed, this, profile, definition, typeUrl));
}
@Override
public String fhirpath() {
String base = definition.getName().replace("[x]", "");
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(" or ");
if (getSlices() != null) {
for (PEDefinition slice : getSlices()) {
b.append("("+builder.makeSliceExpression(slice.profile, definition.getSlicing(), slice.definition())+")");
}
} else if (definition.hasSlicing()) {
List<PEDefinition> slices = builder.listSlices(profile, definition, this);
for (PEDefinition slice : slices) {
b.append("("+builder.makeSliceExpression(profile, definition.getSlicing(), slice.definition())+")");
}
}
if (b.count() == 0)
return base;
else
return base+".where(("+b.toString()+").not())";
}
}

View File

@ -0,0 +1,118 @@
package org.hl7.fhir.r4.profilemodel;
/*
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.List;
import org.hl7.fhir.r4.conformance.ProfileUtilities;
import org.hl7.fhir.r4.model.CanonicalType;
import org.hl7.fhir.r4.model.ElementDefinition;
import org.hl7.fhir.r4.model.ElementDefinition.SlicingRules;
import org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r4.profilemodel.PEDefinition.PEDefinitionElementMode;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.r4.model.StructureDefinition;
public class PEDefinitionExtension extends PEDefinition {
private StructureDefinition extension;
private ElementDefinition sliceDefinition;
private ElementDefinition eed;
private ElementDefinition ved;
public PEDefinitionExtension(PEBuilder builder, String name, StructureDefinition profile, ElementDefinition definition, ElementDefinition sliceDefinition, StructureDefinition extension, String ppath) {
super(builder, name, profile, definition, ppath);
this.sliceDefinition = sliceDefinition;
this.extension= extension;
eed = extension.getSnapshot().getElementByPath("Extension.extension");
ved = extension.getSnapshot().getElementByPath("Extension.value[x]");
}
@Override
public void listTypes(List<PEType> types) {
if (ved.isRequired() || eed.isProhibited()) {
for (TypeRefComponent t : ved.getType()) {
if (t.hasProfile()) {
for (CanonicalType u : t.getProfile()) {
types.add(builder.makeType(t, u));
}
} else {
types.add(builder.makeType(t.getWorkingCode()));
}
}
} else if (ProfileUtilities.isComplexExtension(extension)) {
types.add(builder.makeType(extension.getName(), extension.getUrl()));
} else {
types.add(builder.makeType("Extension"));
}
}
@Override
protected void makeChildren(String typeUrl, List<PEDefinition> children, boolean allFixed) {
if (ved.isRequired() || eed.isProhibited()) {
children.addAll(builder.listChildren(allFixed, this, extension, ved, typeUrl));
} else {
List<PEDefinition> slices = builder.listSlices(extension, eed, this);
if (eed.getSlicing().getRules() != SlicingRules.CLOSED) {
children.addAll(builder.listChildren(allFixed, this, extension, eed, "http://hl7.org/fhir/StructureDefinition/Extension", "value[x]", "url"));
if (!children.isEmpty()) {
children.get(0).setSlices(slices);
}
}
children.addAll(slices);
}
}
@Override
public String fhirpath() {
if (ved.isRequired() || eed.isProhibited()) {
return "extension('"+extension.getUrl()+"').value";
} else {
return "extension('"+extension.getUrl()+"')";
}
}
public PEDefinitionElementMode mode() {
return PEDefinitionElementMode.Extension;
}
public List<PEDefinition> directChildren(boolean allFixed) {
List<PEDefinition> children = new ArrayList<>();
children.addAll(builder.listChildren(allFixed, this, extension, extension.getSnapshot().getElementFirstRep(), "http://hl7.org/fhir/StructureDefinition/Extension"));
return children;
}
public boolean isExtension() {
return true;
}
}

View File

@ -0,0 +1,57 @@
package org.hl7.fhir.r4.profilemodel;
/*
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.List;
import org.hl7.fhir.r4.model.StructureDefinition;
public class PEDefinitionResource extends PEDefinition {
public PEDefinitionResource(PEBuilder builder, StructureDefinition profile, String ppath) {
super(builder, profile.getName(), profile, profile.getSnapshot().getElementFirstRep(), ppath);
}
@Override
public void listTypes(List<PEType> types) {
types.add(new PEType(profile.getName(), profile.getType(), profile.getUrl()));
}
@Override
protected void makeChildren(String typeUrl, List<PEDefinition> children, boolean allFixed) {
children.addAll(builder.listChildren(allFixed, this, profile, definition, null));
}
@Override
public String fhirpath() {
return profile.getType();
}
}

View File

@ -0,0 +1,72 @@
package org.hl7.fhir.r4.profilemodel;
/*
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.List;
import org.hl7.fhir.r4.model.CanonicalType;
import org.hl7.fhir.r4.model.ElementDefinition;
import org.hl7.fhir.r4.model.StructureDefinition;
import org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent;
public class PEDefinitionSlice extends PEDefinition {
protected ElementDefinition sliceDefinition;
public PEDefinitionSlice(PEBuilder builder, String name, StructureDefinition profile, ElementDefinition profileDefinition, ElementDefinition sliceDefinition, String ppath) {
super(builder, name, profile, profileDefinition, ppath);
this.sliceDefinition = sliceDefinition;
}
@Override
public void listTypes(List<PEType> types) {
for (TypeRefComponent t : definition.getType()) {
if (t.hasProfile()) {
for (CanonicalType u : t.getProfile()) {
types.add(builder.makeType(t, u));
}
} else if (!t.getCode().startsWith("http://hl7.org/fhirpath/")) {
types.add(new PEType(t.getWorkingCode(), t.getWorkingCode(), "http://hl7.org/fhir/StructureDefinition/"+t.getWorkingCode()));
}
}
}
@Override
protected void makeChildren(String typeUrl, List<PEDefinition> children, boolean allFixed) {
children.addAll(builder.listChildren(allFixed, this, profile, definition, typeUrl));
}
@Override
public String fhirpath() {
String base = schemaName().replace("[x]", "");
String filter = builder.makeSliceExpression(profile, sliceDefinition.getSlicing(), definition);
return base+".where("+filter+")";
}
}

View File

@ -0,0 +1,117 @@
package org.hl7.fhir.r4.profilemodel;
/*
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.List;
import org.hl7.fhir.r4.model.CanonicalType;
import org.hl7.fhir.r4.model.ElementDefinition;
import org.hl7.fhir.r4.model.ElementDefinition.SlicingRules;
import org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r4.profilemodel.PEDefinition.PEDefinitionElementMode;
import org.hl7.fhir.r4.model.StructureDefinition;
public class PEDefinitionSubExtension extends PEDefinition {
private ElementDefinition eed;
private ElementDefinition ved;
private ElementDefinition ued;
public PEDefinitionSubExtension(PEBuilder builder, StructureDefinition profile, ElementDefinition definition, String ppath) {
super(builder, definition.getSliceName(), profile, definition, ppath);
List<ElementDefinition> childDefs = builder.getChildren(profile, definition);
eed = getElementByName(childDefs, "extension");
ved = getElementByName(childDefs, "value[x]");
ued = getElementByName(childDefs, "url");
}
@Override
public void listTypes(List<PEType> types) {
if (ved.isRequired() || eed.isProhibited()) {
for (TypeRefComponent t : ved.getType()) {
if (t.hasProfile()) {
for (CanonicalType u : t.getProfile()) {
types.add(builder.makeType(t, u));
}
} else {
types.add(builder.makeType(t.getWorkingCode()));
}
}
} else {
types.add(builder.makeType("Extension"));
}
}
private ElementDefinition getElementByName(List<ElementDefinition> children, String name) {
for (ElementDefinition ed : children) {
if (name.equals(ed.getName())) {
return ed;
}
}
return null;
}
public List<PEDefinition> directChildren(boolean allFixed) {
List<PEDefinition> children = new ArrayList<>();
children.addAll(builder.listChildren(allFixed, this, profile, definition, "http://hl7.org/fhir/StructureDefinition/Extension"));
return children;
}
@Override
protected void makeChildren(String typeUrl, List<PEDefinition> children, boolean allFixed) {
if (ved.isRequired() || eed.isProhibited()) {
children.addAll(builder.listChildren(allFixed, this, profile, ved, typeUrl));
} else {
if (eed.getSlicing().getRules() != SlicingRules.CLOSED) {
children.addAll(builder.listChildren(allFixed, this, profile, eed, "http://hl7.org/fhir/StructureDefinition/Extension", "value[x]", "url"));
}
children.addAll(builder.listSlices(profile, eed, this));
}
}
@Override
public String fhirpath() {
if (ved.isRequired() || eed.isProhibited()) {
return "extension('"+ued.getFixed().primitiveValue()+"').value";
} else {
return "extension('"+ued.getFixed().primitiveValue()+"')";
}
}
public PEDefinitionElementMode mode() {
return PEDefinitionElementMode.Extension;
}
public boolean isExtension() {
return true;
}
}

View File

@ -0,0 +1,76 @@
package org.hl7.fhir.r4.profilemodel;
/*
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.List;
import org.hl7.fhir.r4.model.CanonicalType;
import org.hl7.fhir.r4.model.ElementDefinition;
import org.hl7.fhir.r4.model.StructureDefinition;
import org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
public class PEDefinitionTypeSlice extends PEDefinition {
protected ElementDefinition sliceDefinition;
public PEDefinitionTypeSlice(PEBuilder builder, String name, StructureDefinition profile, ElementDefinition definition, ElementDefinition sliceDefinition, String ppath) {
super(builder, name, profile, definition, ppath);
this.sliceDefinition = sliceDefinition;
}
@Override
public void listTypes(List<PEType> types) {
for (TypeRefComponent t : definition.getType()) {
if (t.hasProfile()) {
for (CanonicalType u : t.getProfile()) {
types.add(builder.makeType(t, u));
}
} else if (!t.getCode().startsWith("http://hl7.org/fhirpath/")) {
types.add(new PEType(t.getWorkingCode(), t.getWorkingCode(), "http://hl7.org/fhir/StructureDefinition/"+t.getWorkingCode()));
}
}
}
@Override
protected void makeChildren(String typeUrl, List<PEDefinition> children, boolean allFixed) {
children.addAll(builder.listChildren(allFixed, this, profile, definition, typeUrl));
}
@Override
public String fhirpath() {
String base = definition.getName().replace("[x]", "");
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(" | ");
for (TypeRefComponent t : definition.getType()) {
b.append(base+".ofType("+t.getWorkingCode()+")");
}
return b.toString();
}
}

View File

@ -0,0 +1,310 @@
package org.hl7.fhir.r4.profilemodel;
/*
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.Date;
import java.util.List;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r4.model.Base;
import org.hl7.fhir.r4.model.BaseDateTimeType;
import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.ContactPoint;
import org.hl7.fhir.r4.model.Identifier;
import org.hl7.fhir.r4.model.Type;
import org.hl7.fhir.r4.model.DateTimeType;
import org.hl7.fhir.r4.model.DateType;
import org.hl7.fhir.r4.model.Extension;
import org.hl7.fhir.r4.model.HumanName;
import org.hl7.fhir.r4.context.IWorkerContext;
import org.hl7.fhir.r4.model.Address;
import org.hl7.fhir.r4.model.PrimitiveType;
import org.hl7.fhir.r4.model.Quantity;
import org.hl7.fhir.r4.model.Reference;
import org.hl7.fhir.r4.model.Resource;
import org.hl7.fhir.r4.model.StringType;
/**
* This class provides a profile centric view of a resource, as driven by a profile
*
* This class is also suitable to be used as the base of a POJO
* @author grahamegrieve
*
*/
public class PEInstance {
private PEBuilder builder;
private PEDefinition definition;
private Resource resource; // for FHIRPath
private Base data;
private String path;
protected PEInstance(PEBuilder builder, PEDefinition definition, Resource resource, Base data, String path) {
super();
this.builder = builder;
this.definition = definition;
this.resource = resource;
this.data = data;
this.path = path;
}
/**
* @return definition information about this instance data
*/
public PEDefinition definition() {
return definition;
}
/**
* @return the type of this element
*/
public PEType type() {
return definition.types().get(0);
}
/**
* @return all the children of this instance data
*/
public List<PEInstance> children() {
List<PEInstance> res = new ArrayList<>();
for (PEDefinition child : definition.children()) {
List<Base> instances = builder.exec(resource, data, child.fhirpath());
int i = 0;
for (Base b : instances) {
res.add(new PEInstance(builder, child, resource, b, path+"."+child.name()+(child.repeats() ? "["+i+"]": "")));
i++;
}
}
return res;
}
/**
* @return all the single children of this instance data for the named property. An exception if there's more than one, null if there's none
*/
public PEInstance child(String name) {
PEDefinition child = byName(definition.children(), name);
List<Base> instances = builder.exec(resource, data, child.fhirpath());
if (instances.isEmpty()) {
return null;
} else if (instances.size() == 1) {
return new PEInstance(builder, child, resource, instances.get(0), path+"."+child.name()+(child.repeats() ? "[0]": ""));
} else {
throw new FHIRException("Found multiple instances for "+name+"@ "+path);
}
}
/**
* @return all the children of this instance data for the named property
*/
public List<PEInstance> children(String name) {
PEDefinition child = byName(definition.children(), name);
List<PEInstance> res = new ArrayList<>();
List<Base> instances = builder.exec(resource, data, child.fhirpath());
int i = 0;
for (Base b : instances) {
res.add(new PEInstance(builder, child, resource, b, path+"."+child.name()+(child.repeats() ? "["+i+"]": "")));
i++;
}
return res;
}
private PEDefinition byName(List<PEDefinition> children, String name) {
for (PEDefinition defn : children) {
if (defn.name().equals(name)) {
return defn;
}
if (defn.name().equals(name+"[x]")) {
return defn;
}
}
throw new FHIRException("No children with the name '"+name+"'");
}
/**
* @return make a child, and append it to existing children (if they exist)
*/
public PEInstance makeChild(String name) {
PEDefinition child = byName(definition.children(), name);
Base b = child.isBaseList() || !child.isBasePrimitive() ? data.addChild(child.schemaNameWithType()) : data.makeProperty(child.schemaNameWithType().hashCode(), child.schemaNameWithType());
builder.populateByProfile(b, child);
return new PEInstance(builder, child, resource, b, path+"."+child.name());
}
/**
* @return get a child. if it doesn't exist, make one
*/
public PEInstance forceChild(String name) {
PEDefinition child = byName(definition.children(), name);
List<Base> instances = builder.exec(resource, data, child.fhirpath());
if (instances.isEmpty()) {
Base b = data.addChild(child.schemaName());
builder.populateByProfile(b, child);
return new PEInstance(builder, child, resource, b, path+"."+child.name()+(child.isList() ? "[0]": ""));
} else {
return new PEInstance(builder, child, resource, instances.get(0), path+"."+child.name()+(child.repeats() ? "[0]": ""));
}
}
/**
* remove the nominated child from the resource
*/
public void removeChild(PEInstance child) {
data.removeChild(child.definition().schemaName(), child.data);
}
public void clear(String name) {
List<PEInstance> children = children(name);
for (PEInstance child : children) {
removeChild(child);
}
}
public enum PEInstanceDataKind {
Resource, Complex, DataType, Primitive
}
/**
* @return the kind of data behind this profiled node
*/
public PEInstanceDataKind getDataKind() {
if (data instanceof Resource) {
return PEInstanceDataKind.Resource;
}
if (data instanceof PrimitiveType) {
return PEInstanceDataKind.Primitive;
}
if (data instanceof Type) {
return PEInstanceDataKind.DataType;
}
return PEInstanceDataKind.Complex;
}
public Base data() {
return data;
}
/**
* @return if dataKind = Resource, get the underlying resource, otherwise an exception
*/
public Resource asResource() {
return (Resource) data;
}
/**
* @return if dataKind = Datatype, get the underlying resource, otherwise an exception
*/
public Type asDataType() {
return (Type) data;
}
public CodeableConcept asCodeableConcept() {
return (CodeableConcept) asDataType();
}
public Identifier Identifier() {
return (Identifier) asDataType();
}
public Quantity asQuantity() {
return (Quantity) asDataType();
}
public HumanName asHumanName() {
return (HumanName) asDataType();
}
public Address Address() {
return (Address) asDataType();
}
public ContactPoint asContactPoint() {
return (ContactPoint) asDataType();
}
public Reference asReference() {
return (Reference) asDataType();
}
/**
* @return if dataKind = PrimitiveValue, get the underlying resource, otherwise an exception
*
* Note that this is for e.g. String.value, not String itself
*/
public String getPrimitiveAsString() {
return data.primitiveValue();
}
public Date getPrimitiveAsDate() {
if (data instanceof BaseDateTimeType) {
return ((DateTimeType) data).getValue();
}
return null;
}
public void setPrimitiveValue(String value) {
PrimitiveType<?> pt = (PrimitiveType<?>) data;
pt.setValueAsString(value);
}
public String getPath() {
return path;
}
public Base getBase() {
return data;
}
public boolean hasChild(String name) {
PEDefinition child = byName(definition.children(), name);
List<Base> instances = builder.exec(resource, data, child.fhirpath());
return !instances.isEmpty();
}
public IWorkerContext getContext() {
return builder.getContext();
}
public void addChild(String name, Type value) {
PEDefinition child = byName(definition.children(), name);
Base b = data.setProperty(child.schemaName(), value);
}
public void addChild(String name, String value) {
PEDefinition child = byName(definition.children(), name);
Base b = data.setProperty(child.schemaName(), new StringType(value));
}
public void addChild(String name, Date value) {
PEDefinition child = byName(definition.children(), name);
Base b = data.setProperty(child.schemaName(), new DateType(value));
}
}

View File

@ -0,0 +1,73 @@
package org.hl7.fhir.r4.profilemodel;
/*
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.
*/
public class PEType {
private String name;
private String type;
private String url;
public PEType(String name, String type, String url) {
super();
this.name = name;
this.url = url;
this.type = type;
}
/**
* Human presentable name
*
* @return
*/
public String getName() {
return name;
}
/**
* The concrete FHIR type name for the type
*
* @return
*/
public String getType() {
return type;
}
/**
* URL that identifies the type
* @return
*/
public String getUrl() {
return url;
}
@Override
public String toString() {
return (name.equals(type) ? name : name+"->"+type)+"["+url+"]";
}
}

View File

@ -0,0 +1,650 @@
package org.hl7.fhir.r4.profilemodel.gen;
/*
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.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import java.util.ArrayList;
import java.util.Date;
import org.hl7.fhir.r4.context.IWorkerContext;
import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Identifier;
import org.hl7.fhir.r4.model.Observation;
import org.hl7.fhir.r4.model.StructureDefinition;
import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r4.profilemodel.PEBuilder;
import org.hl7.fhir.r4.profilemodel.PEBuilder.PEElementPropertiesPolicy;
import org.hl7.fhir.r4.profilemodel.gen.PECodeGenerator.ExtensionPolicy;
import org.hl7.fhir.r4.profilemodel.PEDefinition;
import org.hl7.fhir.r4.profilemodel.PEInstance;
import org.hl7.fhir.r4.profilemodel.PEType;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
public class PECodeGenerator {
public static final String DEFAULT_DATE() {
SimpleDateFormat sdf = new SimpleDateFormat("EEE, MMM d, yyyy HH:mmZ", new Locale("en", "US"));
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
return sdf.format(new Date());
}
public enum ExtensionPolicy {
None, Complexes, Primitives;
}
private class PEGenClass {
private String name;
private String base;
private String doco;
private String url;
private boolean isResource;
private StringBuilder fields = new StringBuilder();
private StringBuilder load = new StringBuilder();
private StringBuilder save = new StringBuilder();
private StringBuilder clear = new StringBuilder();
private StringBuilder copy = new StringBuilder();
private StringBuilder accessors = new StringBuilder();
private StringBuilder hash = new StringBuilder();
public void genId() {
if (isResource) {
genField(true, "id", "String", "id", "", false, "");
genAccessors(true, false, "id", "String", "", "String", "String", "Id", "Ids", false, "", false);
genLoad(true, false, "id", "id", "IdType", "", "String", "String", "Id", "Ids", false, false, null);
genSave(true, false, "id", "id", "IdType", "", "String", "String", "Id", "Ids", false, false, false, null);
genClear(false, "id");
}
}
public void write(StringBuilder b, String copyright) {
w(b);
if (copyright != null) {
w(b, "/*");
w(b, copyright);
w(b, " */");
w(b);
}
w(b, "// Generated by the HAPI Java Profile Generator, "+genDate);
w(b);
jdoc(b, doco, 0, true);
w(b, "public class "+name+" extends PEGeneratedBase {");
w(b);
if (url != null) {
w(b, " private static final String CANONICAL_URL = \""+url+"\";");
w(b);
}
w(b, fields.toString());
jdoc(b, "Parameter-less constructor. If you use this, the fixed values won't be filled out - they'll be missing. They'll be filled in if/when you call build, so they won't be missing from the resource, only from this particular object model", 2, true);
w(b, " public "+name+"() {");
w(b, " // todo");
w(b, " }");
w(b);
if (isResource) {
jdoc(b, "Construct an instance of the object, and fill out all the fixed values ", 2, true);
w(b, " public "+name+"(IWorkerContext context) {");
w(b, " workerContext = context;");
w(b, " PEBuilder builder = new PEBuilder(context, PEElementPropertiesPolicy.EXTENSION, true);");
w(b, " PEInstance src = builder.buildPEInstance(CANONICAL_URL, builder.createResource(CANONICAL_URL, false));");
w(b, " load(src);");
w(b, " }");
w(b);
jdoc(b, "Populate an instance of the object based on this source object ", 2, true);
w(b, " public static "+name+" fromSource(IWorkerContext context, "+base+" source) {");
w(b, " "+name+" theThing = new "+name+"();");
w(b, " theThing.workerContext = context;");
w(b, " PEBuilder builder = new PEBuilder(context, PEElementPropertiesPolicy.EXTENSION, true);");
w(b, " PEInstance src = builder.buildPEInstance(CANONICAL_URL, source);");
w(b, " theThing.load(src);");
w(b, " return theThing;");
w(b, " }");
w(b);
} else {
jdoc(b, "Used when loading other models ", 2, true);
w(b, " public static "+name+" fromSource(PEInstance source) {");
w(b, " "+name+" theThing = new "+name+"();");
w(b, " theThing.workerContext = source.getContext();");
w(b, " theThing.load(source);");
w(b, " return theThing;");
w(b, " }");
}
w(b);
w(b, " public void load(PEInstance src) {");
w(b, " clear();");
w(b, load.toString());
w(b, " }");
w(b);
if (isResource) {
jdoc(b, "Build an instance of the object based on this source object ", 2, true);
w(b, " public "+base+" build(IWorkerContext context) {");
w(b, " workerContext = context;");
w(b, " "+base+" theThing = new "+base+"();");
w(b, " PEBuilder builder = new PEBuilder(context, PEElementPropertiesPolicy.EXTENSION, true);");
w(b, " PEInstance tgt = builder.buildPEInstance(CANONICAL_URL, theThing);");
w(b, " save(tgt, false);");
w(b, " return theThing;");
w(b, " }");
w(b);
jdoc(b, "Save this profile class into an existing resource (overwriting enything that exists in the profile) ", 2, true);
w(b, " public void save(IWorkerContext context, "+base+" dest, boolean nulls) {");
w(b, " workerContext = context;");
w(b, " PEBuilder builder = new PEBuilder(context, PEElementPropertiesPolicy.EXTENSION, true);");
w(b, " PEInstance tgt = builder.buildPEInstance(CANONICAL_URL, dest);");
w(b, " save(tgt, nulls);");
w(b, " }");
w(b);
}
w(b, " public void save(PEInstance tgt, boolean nulls) {");
w(b, save.toString());
w(b, " }");
w(b);
w(b, accessors.toString());
w(b);
w(b, " public void clear() {");
w(b, clear.toString());
w(b, " }");
w(b);
w(b, "}");
}
private void defineField(PEDefinition source, PEDefinition field) {
if (field.types().size() == 1) {
StructureDefinition sd = workerContext.fetchTypeDefinition(field.types().get(0).getUrl());
if (sd != null) {
boolean isPrim = sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
boolean isAbstract = sd.getAbstract();
String name = field.name().replace("[x]", "");
String sname = name;
String type = null;
String init = "";
String ptype = type;
if (isPrim) {
// todo: are we extension-less?
type = Utilities.capitalize(field.types().get(0).getName()+"Type");
ptype = getPrimitiveType(sd);
} else {
type = field.types().get(0).getName();
}
String ltype = type;
if (field.isList()) {
ltype = "List<"+type+">";
init = "new ArrayList<>()";
if (!Utilities.existsInList(name, "contained")) {
name = Utilities.pluralize(name, 2);
}
}
String cname = Utilities.capitalize(name);
String csname = Utilities.capitalize(sname);
String nn = field.min() == 1 ? "// @NotNull" : "";
boolean isExtension = field.isExtension();
genField(isPrim, name, ptype, ltype, nn, field.isList(), field.shortDocumentation());
genAccessors(isPrim, isAbstract, name, type, init, ptype, ltype, cname, csname, field.isList(), field.documentation(), field.fixedValue());
genLoad(isPrim, isAbstract, name, sname, type, init, ptype, ltype, cname, csname, field.isList(), field.fixedValue(), field.types().get(0));
genSave(isPrim, isAbstract, name, sname, type, init, ptype, ltype, cname, csname, field.isList(), field.fixedValue(), isExtension, field.types().get(0));
genClear(field.isList(), name);
}
} else {
// ignoring polymorphics for now
}
}
private void genClear(boolean list, String name) {
if (list) {
w(clear, " "+name+".clear();");
} else {
w(clear, " "+name+" = null;");
}
}
private void genLoad(boolean isPrim, boolean isAbstract, String name, String sname, String type, String init, String ptype, String ltype, String cname, String csname, boolean isList, boolean isFixed, PEType typeInfo) {
if (isList) {
w(load, " for (PEInstance item : src.children(\""+sname+"\")) {");
w(load, " "+name+".add(("+type+") item.asDataType());");
w(load, " }");
} else if (isPrim) {
w(load, " if (src.hasChild(\""+name+"\")) {");
if ("CodeType".equals(type)) {
// might be code or enum
w(load, " "+name+" = src.child(\""+name+"\").asDataType().primitiveValue();");
} else {
w(load, " "+name+" = (("+type+") src.child(\""+name+"\").asDataType()).getValue();");
}
w(load, " }");
} else if (typeInfo != null && typeInfo.getUrl() != null && !typeInfo.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition")) {
w(load, " if (src.hasChild(\""+name+"\")) {");
w(load, " "+name+" = "+type+".fromSource(src.child(\""+name+"\"));");
w(load, " }");
} else {
w(load, " if (src.hasChild(\""+name+"\")) {");
w(load, " "+name+" = ("+type+") src.child(\""+name+"\").asDataType();");
w(load, " }");
}
}
private void genSave(boolean isPrim, boolean isAbstract, String name, String sname, String type, String init, String ptype, String ltype, String cname, String csname, boolean isList, boolean isFixed, boolean isExtension, PEType typeInfo) {
w(save, " tgt.clear(\""+sname+"\");");
if (isList) {
w(save, " for ("+type+" item : "+name+") {");
if (isExtension) {
w(save, " tgt.makeChild(\""+sname+"\").data().setProperty(\"value[x]\", item);");
} else {
w(save, " tgt.addChild(\""+sname+"\", item);");
}
w(save, " }");
} else if (isPrim) {
w(save, " if ("+name+" != null) {");
if (isExtension) {
w(save, " tgt.makeChild(\""+sname+"\").data().setProperty(\"value[x]\", new "+type+"("+name+"));");
} else if (Utilities.existsInList(type, "DateType", "InstantType", "DateTimeType")) {
w(save, " tgt.addChild(\""+sname+"\", new "+type+"("+name+"));");
} else {
w(save, " tgt.makeChild(\""+sname+"\").data().setProperty(\"value\", new "+type+"("+name+"));");
}
w(save, " }");
} else if (typeInfo != null && typeInfo.getUrl() != null && !typeInfo.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition")) {
w(save, " if ("+name+" != null) {");
w(save, " "+name+".save(tgt.makeChild(\""+sname+"\"), nulls);");
w(save, " }");
} else if (isExtension) {
w(save, " if ("+name+" != null) {");
w(save, " tgt.makeChild(\""+sname+"\").data().setProperty(\"value[x]\", "+name+");");
w(save, " }");
} else {
w(save, " if ("+name+" != null) {");
w(save, " tgt.addChild(\""+sname+"\", "+name+");");
w(save, " }");
}
}
private void genAccessors(boolean isPrim, boolean isAbstract, String name, String type, String init, String ptype, String ltype, String cname, String csname, boolean isList, String shortDoco, boolean isFixed) {
jdoc(accessors, doco, 2, true);
if (isPrim && extensionPolicy != ExtensionPolicy.Primitives && !isList) {
w(accessors, " public "+ptype+" get"+cname+"() {");
w(accessors, " return "+name+";");
w(accessors, " }");
w(accessors);
w(accessors, " public "+this.name+" set"+cname+"("+ptype+" value) {");
w(accessors, " this."+name+" = value;");
w(accessors, " return this;");
w(accessors, " }");
w(accessors);
w(accessors, " public boolean has"+cname+"() {");
w(accessors, " return "+name+" != null;");
w(accessors, " }");
} else {
if (isPrim && !isList) {
w(accessors, " public "+ptype+" get"+cname+"() {");
w(accessors, " if ("+name+" == null) { "+name+" = new "+type+"(); }");
w(accessors, " return "+name+".getValue();");
w(accessors, " }");
w(accessors, " public "+ltype+" get"+cname+"Element() {");
} else if (isAbstract && !isList) {
w(accessors, " public @Nullable "+ltype+" get"+cname+"() { // "+ltype+" is abstract ");
} else {
w(accessors, " public "+ltype+" get"+cname+"() {");
}
if (isList) {
w(accessors, " if ("+name+" == null) { "+name+" = "+init+"; }");
} else if (!isAbstract) {
w(accessors, " if ("+name+" == null) { "+name+" = new "+type+"(); }");
}
w(accessors, " return "+name+";");
w(accessors, " }");
w(accessors);
if (isList) {
w(accessors, " public boolean has"+cname+"() {");
w(accessors, " return "+name+" != null && !"+name+".isEmpty();");
w(accessors, " }");
w(accessors);
if (!isAbstract) {
w(accessors, " public "+type+" add"+csname+"() {");
w(accessors, " "+type+" theThing = new "+type+"();");
w(accessors, " get"+cname+"().add(theThing);");
w(accessors, " return theThing;");
w(accessors, " }");
w(accessors);
}
w(accessors, " public boolean has"+csname+"("+type+" item) {");
w(accessors, " return has"+cname+"() && "+name+".contains(item);");
w(accessors, " }");
w(accessors);
w(accessors, " public void remove"+csname+"("+type+" item) {");
w(accessors, " if (has"+csname+"(item)) {");
w(accessors, " "+name+".remove(item);");
w(accessors, " }");
w(accessors, " }");
w(accessors);
} else if (isPrim) {
if (!isFixed) {
w(accessors, " public "+this.name+" set"+cname+"("+ptype+" value) {");
w(accessors, " if ("+name+" == null) { "+name+" = new "+type+"(); }");
w(accessors, " "+name+".setValue(value);");
w(accessors, " return this;");
w(accessors, " }");
w(accessors, " public "+this.name+" set"+cname+"Element("+type+" value) {");
w(accessors, " this."+name+" = value;");
w(accessors, " return this;");
w(accessors, " }");
}
w(accessors, " public boolean has"+cname+"() {");
w(accessors, " return "+name+" != null && "+name+".hasValue();");
w(accessors, " }");
w(accessors);
} else {
if (!isFixed) {
w(accessors, " public "+this.name+" set"+cname+"("+type+" value) {");
w(accessors, " this."+name+" = value;");
w(accessors, " return this;");
w(accessors, " }");
}
w(accessors, " public boolean has"+cname+"() {");
w(accessors, " return "+name+" != null;");
w(accessors, " }");
}
}
w(accessors);
}
private void genField(boolean isPrim, String name, String ptype, String ltype, String nn, boolean isList, String shortDoco) {
// jdoc(fields, field.documentation(), 2, true);
if (isPrim && extensionPolicy != ExtensionPolicy.Primitives && !isList) {
w(fields, " private "+ptype+" "+name+";"+nn+" // "+shortDoco);
} else if (isList) {
w(fields, " private "+ltype+" "+name+" = new ArrayList<>();"+nn+" // "+shortDoco);
} else {
w(fields, " private "+ltype+" "+name+";"+nn+" // "+shortDoco);
}
}
}
private String folder;
private IWorkerContext workerContext;
private String canonical;
private String pkgName;
// options:
private ExtensionPolicy extensionPolicy;
private boolean narrative;
private boolean contained;
private boolean meta;
private String language;
private boolean keyElementsOnly;
private String genDate = DEFAULT_DATE();
public PECodeGenerator(IWorkerContext workerContext) {
super();
this.workerContext = workerContext;
}
public String getFolder() {
return folder;
}
public void setFolder(String folder) {
this.folder = folder;
}
public String getCanonical() {
return canonical;
}
public void setCanonical(String canonical) {
this.canonical = canonical;
}
public String getPkgName() {
return pkgName;
}
public void setPkgName(String pkgName) {
this.pkgName = pkgName;
}
public ExtensionPolicy getExtensionPolicy() {
return extensionPolicy;
}
public void setExtensionPolicy(ExtensionPolicy extensionPolicy) {
this.extensionPolicy = extensionPolicy;
}
public boolean isNarrative() {
return narrative;
}
public void setNarrative(boolean narrative) {
this.narrative = narrative;
}
public boolean isMeta() {
return meta;
}
public void setMeta(boolean meta) {
this.meta = meta;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public boolean isKeyElementsOnly() {
return keyElementsOnly;
}
public void setKeyElementsOnly(boolean keyElementsOnly) {
this.keyElementsOnly = keyElementsOnly;
}
public boolean isContained() {
return contained;
}
public void setContained(boolean contained) {
this.contained = contained;
}
public String getGenDate() {
return genDate;
}
public void setGenDate(String genDate) {
this.genDate = genDate;
}
private StringBuilder imports = new StringBuilder();
/**
* @throws IOException
*
*/
public void execute() throws IOException {
PEDefinition source = new PEBuilder(workerContext, PEElementPropertiesPolicy.EXTENSION, true).buildPEDefinition(canonical);
w(imports, "import java.util.List;");
w(imports, "import java.util.ArrayList;");
w(imports, "import javax.annotation.Nullable;");
w(imports, "import java.util.Date;\r\n");
w(imports);
w(imports, "import org.hl7.fhir.r5.context.IWorkerContext;");
w(imports, "import org.hl7.fhir.r5.model.*;");
w(imports, "import org.hl7.fhir.r5.profilemodel.PEBuilder;");
w(imports, "import org.hl7.fhir.r5.profilemodel.PEInstance;");
w(imports, "import org.hl7.fhir.r5.profilemodel.PEBuilder.PEElementPropertiesPolicy;");
w(imports, "import org.hl7.fhir.r5.profilemodel.gen.PEGeneratedBase;");
PEGenClass cls = genClass(source);
StringBuilder b = new StringBuilder();
w(b, "package "+pkgName+";");
w(b);
if (source.getProfile().hasCopyright()) {
jdoc(b, source.getProfile().getCopyright(), 0, false);
}
w(b, imports.toString());
cls.write(b, source.getProfile().getCopyright());
TextFile.stringToFile(b.toString(), Utilities.path(folder, cls.name+".java"));
}
public void jdoc(StringBuilder b, String doco, int indent, boolean jdoc) {
if (!Utilities.noString(doco)) {
String pfx = Utilities.padLeft("", ' ', indent);
w(b, pfx+"/*"+(jdoc ? "*" : ""));
for (String line : doco.split("\\R")) {
for (String nl : naturalLines(line))
w(b, pfx+" * "+nl);
w(b, pfx+" *");
}
w(b, pfx+" */");
}
}
private List<String> naturalLines(String line) {
List<String> lines = new ArrayList<>();
while (line.length() > 80) {
int cutpoint = 80;
while (cutpoint > 0 && line.charAt(cutpoint) != ' ') {
cutpoint--;
}
if (cutpoint == 0) {
cutpoint = 80;
} else {
cutpoint++;
}
lines.add(line.substring(0, cutpoint));
line = line.substring(cutpoint);
}
lines.add(line);
return lines;
}
private void w(StringBuilder b) {
b.append("\r\n");
}
private void w(StringBuilder b, String line) {
b.append(line);
w(b);
}
private PEGenClass genClass(PEDefinition source) {
PEGenClass cls = new PEGenClass();
cls.name = source.getProfile().getName();
cls.base = source.getProfile().getType();
cls.doco = source.documentation();
cls.url = source.getProfile().getVersionedUrl();
cls.isResource = source.getProfile().getKind() == StructureDefinitionKind.RESOURCE;
cls.genId();
for (PEDefinition child : source.children()) {
if (genForField(source, child)) {
cls.defineField(source, child);
}
}
return cls;
}
private boolean genForField(PEDefinition source, PEDefinition child) {
if (child.definition().getBase().getPath().equals("Resource.meta")) {
return meta;
}
if (child.definition().getBase().getPath().equals("DomainResource.text")) {
return narrative;
}
if (child.definition().getBase().getPath().equals("Resource.language")) {
return language == null;
}
if (child.definition().getBase().getPath().endsWith(".extension") || child.definition().getBase().getPath().endsWith(".modifierExtension")) {
return extensionPolicy == ExtensionPolicy.Complexes;
}
if (child.definition().getBase().getPath().equals("DomainResource.contained")) {
return contained;
}
return !keyElementsOnly || (child.isKeyElement());
}
private String getPrimitiveType(StructureDefinition sd) {
if (sd.getType().equals("string"))
return "String";
if (sd.getType().equals("code"))
return "String";
if (sd.getType().equals("markdown"))
return "String";
if (sd.getType().equals("base64Binary"))
return "byte[]";
if (sd.getType().equals("uri"))
return "String";
if (sd.getType().equals("url"))
return "String";
if (sd.getType().equals("canonical"))
return "String";
if (sd.getType().equals("oid"))
return "String";
if (sd.getType().equals("integer"))
return "int";
if (sd.getType().equals("integer64"))
return "long";
if (sd.getType().equals("unsignedInt"))
return "int";
if (sd.getType().equals("positiveInt"))
return "int";
if (sd.getType().equals("boolean"))
return "boolean";
if (sd.getType().equals("decimal"))
return "BigDecimal";
if (sd.getType().equals("dateTime"))
return "Date";
if (sd.getType().equals("date"))
return "Date";
if (sd.getType().equals("id"))
return "String";
if (sd.getType().equals("instant"))
return "Date";
if (sd.getType().equals("time"))
return "String";
return "??";
}
}

View File

@ -0,0 +1,68 @@
package org.hl7.fhir.r4.profilemodel.gen;
/*
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 org.hl7.fhir.r4.context.IWorkerContext;
import org.hl7.fhir.r4.model.Base;
import org.hl7.fhir.r4.profilemodel.PEInstance;
public class PEGeneratedBase {
protected IWorkerContext workerContext;
@Deprecated
protected PEInstance instance;
@Deprecated
protected void removeChild(String name) {
PEInstance child = instance.child(name);
if (child != null) {
instance.removeChild(child);
}
}
@Deprecated
protected void removeChildren(String name) {
for (PEInstance child : instance.children(name)) {
instance.removeChild(child);
}
}
@Deprecated
public PEInstance getInstance() {
return instance;
}
@Deprecated
public Base getData() {
return instance.getBase();
}
}