Get PE Mode compiling in R4
This commit is contained in:
parent
e819ea6e8f
commit
272c3c1229
|
@ -5268,5 +5268,31 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
public void setDebug(boolean debug) {
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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())";
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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+")";
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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+"]";
|
||||
}
|
||||
|
||||
}
|
|
@ -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 "??";
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue