diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEBuilder.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEBuilder.java index 4dd63fd30..16317f63b 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEBuilder.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEBuilder.java @@ -30,7 +30,7 @@ import org.hl7.fhir.utilities.Utilities; * *** 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 seemless tree. There's two views: + * 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 diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEDefinition.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEDefinition.java index c38afca20..970a8056a 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEDefinition.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEDefinition.java @@ -294,6 +294,26 @@ public abstract class PEDefinition { 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; + } + } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEInstance.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEInstance.java index 184e49c53..650a1535e 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEInstance.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEInstance.java @@ -13,6 +13,7 @@ import org.hl7.fhir.r5.model.Identifier; import org.hl7.fhir.r5.model.DataType; import org.hl7.fhir.r5.model.DateTimeType; import org.hl7.fhir.r5.model.HumanName; +import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.model.Address; import org.hl7.fhir.r5.model.PrimitiveType; import org.hl7.fhir.r5.model.Quantity; @@ -240,4 +241,14 @@ public class PEInstance { public Base getBase() { return data; } + + public boolean hasChild(String name) { + PEDefinition child = byName(definition.children(), name); + List instances = builder.exec(resource, data, child.fhirpath()); + return !instances.isEmpty(); + } + + public IWorkerContext getContext() { + return builder.getContext(); + } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/gen/PECodeGenerator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/gen/PECodeGenerator.java new file mode 100644 index 000000000..70f1f6aa4 --- /dev/null +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/gen/PECodeGenerator.java @@ -0,0 +1,549 @@ +package org.hl7.fhir.r5.profilemodel.gen; + +import java.io.File; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.List; +import java.util.Locale; +import java.util.ArrayList; +import java.util.Date; + +import org.hl7.fhir.r5.context.IWorkerContext; +import org.hl7.fhir.r5.model.CodeableConcept; +import org.hl7.fhir.r5.model.Identifier; +import org.hl7.fhir.r5.model.Observation; +import org.hl7.fhir.r5.model.StructureDefinition; +import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; +import org.hl7.fhir.r5.profilemodel.PEBuilder; +import org.hl7.fhir.r5.profilemodel.PEBuilder.PEElementPropertiesPolicy; +import org.hl7.fhir.r5.profilemodel.gen.PECodeGenerator.ExtensionPolicy; +import org.hl7.fhir.r5.profilemodel.PEDefinition; +import org.hl7.fhir.r5.profilemodel.PEInstance; +import org.hl7.fhir.r5.profilemodel.PEType; +import org.hl7.fhir.utilities.TextFile; +import org.hl7.fhir.utilities.Utilities; + +public class PECodeGenerator { + + public enum ExtensionPolicy { + None, Complexes, Primitives; + } + public static final SimpleDateFormat DATE_FORMAT() { + return new SimpleDateFormat("EEE, MMM d, yyyy HH:mmZ", new Locale("en", "US")); + } + 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", "IdType", "", "String", "String", "Id", "Ids", false, false, null); + genClear(false, "id"); + } + } + public void write(StringBuilder b) { + w(b); + w(b, "// Generated by the HAPI Java Profile Generator, "+DATE_FORMAT().format(new Date())); + 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" : ""; + 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, type, init, ptype, ltype, cname, csname, field.isList(), field.fixedValue(), field.types().get(0)); + genClear(field.isList(), name); + } + } else { + // ignoring polymorphics for now + } + + } + + private void genClear(boolean list, String name) { + w(clear, " "+name+" = null;"); + } + private void genLoad(boolean isPrim, boolean isAbstract, String name, 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(\""+name+"\")) {"); + w(load, " "+name+".add(("+type+") item.asDataType());"); + w(load, " }"); + } else if (isPrim) { + w(load, " if (src.hasChild(\""+name+"\")) {"); + 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 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 { + 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; + + 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; + } + + 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); + 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 naturalLines(String line) { + List 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 "??"; + } + +} diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/gen/PEGeneratedBase.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/gen/PEGeneratedBase.java index b36130735..f576261ab 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/gen/PEGeneratedBase.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/gen/PEGeneratedBase.java @@ -1,12 +1,17 @@ package org.hl7.fhir.r5.profilemodel.gen; +import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.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) { @@ -14,16 +19,19 @@ public class PEGeneratedBase { } } + @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(); } diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/profiles/PETests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/profiles/PETests.java index a4da8cd6a..a8d999ec6 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/profiles/PETests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/profiles/PETests.java @@ -1,5 +1,6 @@ package org.hl7.fhir.r5.profiles; +import java.io.File; import java.io.IOException; import java.util.List; @@ -13,6 +14,8 @@ import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.profilemodel.PEDefinition; import org.hl7.fhir.r5.profilemodel.PEInstance; import org.hl7.fhir.r5.profilemodel.PEType; +import org.hl7.fhir.r5.profilemodel.gen.PECodeGenerator; +import org.hl7.fhir.r5.profilemodel.gen.PECodeGenerator.ExtensionPolicy; import org.hl7.fhir.r5.profilemodel.gen.ProfileExample; import org.hl7.fhir.r5.profilemodel.gen.ProfileExample.LOINCCodesForCholesterolInSerumPlasma; import org.hl7.fhir.r5.profilemodel.gen.ProfileExample.ProfileExampleComplex; @@ -370,5 +373,22 @@ public class PETests { Assertions.assertEquals("Another string value", sl3.getSlice3b().get(0).primitiveValue()); } - + + @Test + public void testGenerate() throws IOException { + load(); + PECodeGenerator gen = new PECodeGenerator(ctxt); + gen.setFolder(Utilities.path("[tmp]")); + gen.setCanonical("http://hl7.org/fhir/test/StructureDefinition/pe-profile1"); + gen.setPkgName("org.hl7.fhir.r5.profiles"); + gen.setExtensionPolicy(ExtensionPolicy.None); + gen.setNarrative(false); + gen.setMeta(false); + gen.setLanguage("en-AU"); + gen.setContained(false); + gen.setKeyELementsOnly(true); + gen.execute(); + gen.setCanonical("http://hl7.org/fhir/test/StructureDefinition/pe-profile2"); + gen.execute(); + } } diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/profiles/TestDatatypeProfile.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/profiles/TestDatatypeProfile.java new file mode 100644 index 000000000..018dacfc5 --- /dev/null +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/profiles/TestDatatypeProfile.java @@ -0,0 +1,203 @@ +package org.hl7.fhir.r5.profiles; + +import java.util.List; +import java.util.ArrayList; +import javax.annotation.Nullable; +import java.util.Date; + + +import org.hl7.fhir.r5.context.IWorkerContext; +import org.hl7.fhir.r5.model.*; +import org.hl7.fhir.r5.profilemodel.PEBuilder; +import org.hl7.fhir.r5.profilemodel.PEInstance; +import org.hl7.fhir.r5.profilemodel.PEBuilder.PEElementPropertiesPolicy; +import org.hl7.fhir.r5.profilemodel.gen.PEGeneratedBase; +import java.util.List; +import java.util.ArrayList; +import javax.annotation.Nullable; +import java.util.Date; + + +import org.hl7.fhir.r5.context.IWorkerContext; +import org.hl7.fhir.r5.model.*; +import org.hl7.fhir.r5.profilemodel.PEBuilder; +import org.hl7.fhir.r5.profilemodel.PEInstance; +import org.hl7.fhir.r5.profilemodel.PEBuilder.PEElementPropertiesPolicy; +import org.hl7.fhir.r5.profilemodel.gen.PEGeneratedBase; + + +// Generated by the HAPI Java Profile Generator, Sun, Aug 20, 2023 19:05+1000 + +/** + * Test CodeableConcept Profile. + * + */ +public class TestDatatypeProfile extends PEGeneratedBase { + + private static final String CANONICAL_URL = "http://hl7.org/fhir/test/StructureDefinition/pe-profile2|0.1"; + + private List codings;// @NotNull // Code defined by a terminology system + private List snomedcts;// @NotNull // Code defined by a terminology system + private List loincs; // Code defined by a terminology system + private String text;// @NotNull // Plain text representation of the concept + + /** + * 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 + * + */ + public TestDatatypeProfile() { + // todo + } + + /** + * Used when loading other models + * + */ + public static TestDatatypeProfile fromSource(PEInstance source) { + TestDatatypeProfile theThing = new TestDatatypeProfile(); + theThing.workerContext = source.getContext(); + theThing.load(source); + return theThing; + } + + public void load(PEInstance src) { + clear(); + for (PEInstance item : src.children("codings")) { + codings.add((Coding) item.asDataType()); + } + for (PEInstance item : src.children("snomedcts")) { + snomedcts.add((Coding) item.asDataType()); + } + for (PEInstance item : src.children("loincs")) { + loincs.add((Coding) item.asDataType()); + } + if (src.hasChild("text")) { + text = ((StringType) src.child("text").asDataType()).getValue(); + } + + } + + public void save(PEInstance tgt, boolean nulls) { + + } + + /** + * Test CodeableConcept Profile. + * + */ + public List getCodings() { + if (codings == null) { codings = new ArrayList<>(); } + return codings; + } + + public boolean hasCodings() { + return codings != null && !codings.isEmpty(); + } + + public Coding addCoding() { + Coding theThing = new Coding(); + getCodings().add(theThing); + return theThing; + } + + public boolean hasCoding(Coding item) { + return hasCodings() && codings.contains(item); + } + + public void removeCoding(Coding item) { + if (hasCoding(item)) { + codings.remove(item); + } + } + + + /** + * Test CodeableConcept Profile. + * + */ + public List getSnomedcts() { + if (snomedcts == null) { snomedcts = new ArrayList<>(); } + return snomedcts; + } + + public boolean hasSnomedcts() { + return snomedcts != null && !snomedcts.isEmpty(); + } + + public Coding addSnomedct() { + Coding theThing = new Coding(); + getSnomedcts().add(theThing); + return theThing; + } + + public boolean hasSnomedct(Coding item) { + return hasSnomedcts() && snomedcts.contains(item); + } + + public void removeSnomedct(Coding item) { + if (hasSnomedct(item)) { + snomedcts.remove(item); + } + } + + + /** + * Test CodeableConcept Profile. + * + */ + public List getLoincs() { + if (loincs == null) { loincs = new ArrayList<>(); } + return loincs; + } + + public boolean hasLoincs() { + return loincs != null && !loincs.isEmpty(); + } + + public Coding addLoinc() { + Coding theThing = new Coding(); + getLoincs().add(theThing); + return theThing; + } + + public boolean hasLoinc(Coding item) { + return hasLoincs() && loincs.contains(item); + } + + public void removeLoinc(Coding item) { + if (hasLoinc(item)) { + loincs.remove(item); + } + } + + + /** + * Test CodeableConcept Profile. + * + */ + public String getText() { + return text; + } + + public TestDatatypeProfile setText(String value) { + this.text = value; + return this; + } + + public boolean hasText() { + return text != null; + } + + + + public void clear() { + codings = null; + snomedcts = null; + loincs = null; + text = null; + + } + +} diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/profiles/TestProfile.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/profiles/TestProfile.java new file mode 100644 index 000000000..47c0863a1 --- /dev/null +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/profiles/TestProfile.java @@ -0,0 +1,335 @@ +package org.hl7.fhir.r5.profiles; + +/* + * Licensed under CC0 1.0 Universal (CC0 1.0). + * + * The person who associated a work with this deed has dedicated the work to the + * public domain by waiving all of his or her rights to the work worldwide under + * copyright law, including all related and neighboring rights, to the extent + * allowed by law. + * + * You can copy, modify, distribute and perform the work, even for commercial + * purposes, all without asking permission. See Other Information below. + * + */ +import java.util.List; +import java.util.ArrayList; +import javax.annotation.Nullable; +import java.util.Date; + + +import org.hl7.fhir.r5.context.IWorkerContext; +import org.hl7.fhir.r5.model.*; +import org.hl7.fhir.r5.profilemodel.PEBuilder; +import org.hl7.fhir.r5.profilemodel.PEInstance; +import org.hl7.fhir.r5.profilemodel.PEBuilder.PEElementPropertiesPolicy; +import org.hl7.fhir.r5.profilemodel.gen.PEGeneratedBase; + + +// Generated by the HAPI Java Profile Generator, Sun, Aug 20, 2023 19:01+1000 + +/** + * Test Observation Profile. + * + */ +public class TestProfile extends PEGeneratedBase { + + private static final String CANONICAL_URL = "http://hl7.org/fhir/test/StructureDefinition/pe-profile1|0.1"; + + private String id; // + private List identifiers; // Business Identifier for observation + private String status;// @NotNull // registered | preliminary | final | amended + + private CodeableConcept code;// @NotNull // Sexual Orientation + private Reference subject;// @NotNull // Who and/or what the observation is about + private Reference encounter; // Healthcare event during which this observation is made + private Date effective;// @NotNull // Clinically relevant time/time-period for observation + private List performers; // Who is responsible for the observation + private TestDatatypeProfile valueCodeableConcept; // Sexual Orientation + + /** + * 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 + * + */ + public TestProfile() { + // todo + } + + /** + * Construct an instance of the object, and fill out all the fixed values + * + */ + public TestProfile(IWorkerContext context) { + workerContext = context; + PEBuilder builder = new PEBuilder(context, PEElementPropertiesPolicy.EXTENSION, true); + PEInstance src = builder.buildPEInstance(CANONICAL_URL, builder.createResource(CANONICAL_URL, false)); + load(src); + } + + /** + * Populate an instance of the object based on this source object + * + */ + public static TestProfile fromSource(IWorkerContext context, Observation source) { + TestProfile theThing = new TestProfile(); + theThing.workerContext = context; + PEBuilder builder = new PEBuilder(context, PEElementPropertiesPolicy.EXTENSION, true); + PEInstance src = builder.buildPEInstance(CANONICAL_URL, source); + theThing.load(src); + return theThing; + } + + + public void load(PEInstance src) { + clear(); + if (src.hasChild("id")) { + id = ((IdType) src.child("id").asDataType()).getValue(); + } + for (PEInstance item : src.children("identifiers")) { + identifiers.add((Identifier) item.asDataType()); + } + if (src.hasChild("status")) { + status = ((CodeType) src.child("status").asDataType()).getValue(); + } + if (src.hasChild("code")) { + code = (CodeableConcept) src.child("code").asDataType(); + } + if (src.hasChild("subject")) { + subject = (Reference) src.child("subject").asDataType(); + } + if (src.hasChild("encounter")) { + encounter = (Reference) src.child("encounter").asDataType(); + } + if (src.hasChild("effective")) { + effective = ((DateTimeType) src.child("effective").asDataType()).getValue(); + } + for (PEInstance item : src.children("performers")) { + performers.add((Reference) item.asDataType()); + } + if (src.hasChild("valueCodeableConcept")) { + valueCodeableConcept = TestDatatypeProfile.fromSource(src.child("valueCodeableConcept")); + } + + } + + /** + * Build an instance of the object based on this source object + * + */ + public Observation build(IWorkerContext context) { + workerContext = context; + Observation theThing = new Observation(); + PEBuilder builder = new PEBuilder(context, PEElementPropertiesPolicy.EXTENSION, true); + PEInstance tgt = builder.buildPEInstance(CANONICAL_URL, theThing); + save(tgt, false); + return theThing; + } + + /** + * Save this profile class into an existing resource (overwriting enything that + * exists in the profile) + * + */ + public void save(IWorkerContext context, Observation dest, boolean nulls) { + workerContext = context; + PEBuilder builder = new PEBuilder(context, PEElementPropertiesPolicy.EXTENSION, true); + PEInstance tgt = builder.buildPEInstance(CANONICAL_URL, dest); + save(tgt, nulls); + } + + public void save(PEInstance tgt, boolean nulls) { + + } + + /** + * Test Observation Profile. + * + */ + public String getId() { + return id; + } + + public TestProfile setId(String value) { + this.id = value; + return this; + } + + public boolean hasId() { + return id != null; + } + + /** + * Test Observation Profile. + * + */ + public List getIdentifiers() { + if (identifiers == null) { identifiers = new ArrayList<>(); } + return identifiers; + } + + public boolean hasIdentifiers() { + return identifiers != null && !identifiers.isEmpty(); + } + + public Identifier addIdentifier() { + Identifier theThing = new Identifier(); + getIdentifiers().add(theThing); + return theThing; + } + + public boolean hasIdentifier(Identifier item) { + return hasIdentifiers() && identifiers.contains(item); + } + + public void removeIdentifier(Identifier item) { + if (hasIdentifier(item)) { + identifiers.remove(item); + } + } + + + /** + * Test Observation Profile. + * + */ + public String getStatus() { + return status; + } + + public TestProfile setStatus(String value) { + this.status = value; + return this; + } + + public boolean hasStatus() { + return status != null; + } + + /** + * Test Observation Profile. + * + */ + public CodeableConcept getCode() { + if (code == null) { code = new CodeableConcept(); } + return code; + } + + public boolean hasCode() { + return code != null; + } + + /** + * Test Observation Profile. + * + */ + public Reference getSubject() { + if (subject == null) { subject = new Reference(); } + return subject; + } + + public TestProfile setSubject(Reference value) { + this.subject = value; + return this; + } + public boolean hasSubject() { + return subject != null; + } + + /** + * Test Observation Profile. + * + */ + public Reference getEncounter() { + if (encounter == null) { encounter = new Reference(); } + return encounter; + } + + public TestProfile setEncounter(Reference value) { + this.encounter = value; + return this; + } + public boolean hasEncounter() { + return encounter != null; + } + + /** + * Test Observation Profile. + * + */ + public Date getEffective() { + return effective; + } + + public TestProfile setEffective(Date value) { + this.effective = value; + return this; + } + + public boolean hasEffective() { + return effective != null; + } + + /** + * Test Observation Profile. + * + */ + public List getPerformers() { + if (performers == null) { performers = new ArrayList<>(); } + return performers; + } + + public boolean hasPerformers() { + return performers != null && !performers.isEmpty(); + } + + public Reference addPerformer() { + Reference theThing = new Reference(); + getPerformers().add(theThing); + return theThing; + } + + public boolean hasPerformer(Reference item) { + return hasPerformers() && performers.contains(item); + } + + public void removePerformer(Reference item) { + if (hasPerformer(item)) { + performers.remove(item); + } + } + + + /** + * Test Observation Profile. + * + */ + public TestDatatypeProfile getValueCodeableConcept() { + if (valueCodeableConcept == null) { valueCodeableConcept = new TestDatatypeProfile(); } + return valueCodeableConcept; + } + + public TestProfile setValueCodeableConcept(TestDatatypeProfile value) { + this.valueCodeableConcept = value; + return this; + } + public boolean hasValueCodeableConcept() { + return valueCodeableConcept != null; + } + + + + public void clear() { + id = null; + identifiers = null; + status = null; + code = null; + subject = null; + encounter = null; + effective = null; + performers = null; + valueCodeableConcept = null; + + } + +}