1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package ca.uhn.hl7v2.sourcegen;
28
29 import java.io.*;
30 import java.net.URL;
31 import java.nio.charset.StandardCharsets;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.Iterator;
35 import java.util.List;
36
37 import ca.uhn.hl7v2.Version;
38 import ca.uhn.hl7v2.parser.DefaultModelClassFactory;
39 import ca.uhn.hl7v2.sourcegen.util.VelocityFactory;
40 import com.sun.xml.xsom.*;
41 import com.sun.xml.xsom.parser.XSOMParser;
42 import org.apache.velocity.Template;
43 import org.apache.velocity.VelocityContext;
44 import org.apache.velocity.context.Context;
45
46
47
48
49
50
51
52
53
54
55 public class XsdDataTypeGenerator {
56
57 private static final String[] PRIMITIVES = {"FT", "GTS", "NM", "SI", "ST", "TN", "TX"};
58 private static final String[] EXCLUDE_COMPOSITES = {"TX_CHALLENGE", "escapeType", "varies"};
59
60 public static final String URN_HL7_ORG_V2XML = "urn:hl7-org:v2xml";
61
62 private final String templatePackage;
63 private final String targetDirectory;
64
65 public XsdDataTypeGenerator(String dir, String templatePackage) throws IOException {
66 File f = new File(dir);
67 if (!f.isDirectory())
68 throw new IOException("Can't create file in " +
69 dir + " - it is not a directory.");
70 this.targetDirectory = dir;
71 this.templatePackage = templatePackage.replace(".", "/");
72 }
73
74 public void parse(Version version) throws Exception {
75 XSOMParser parser = new XSOMParser();
76 String dir = String.format("/hl7v2xsd/%s/datatypes.xsd", version.getVersion());
77 URL url = getClass().getResource(dir);
78 parser.parse(url);
79 XSSchemaSet result = parser.getResult();
80 Iterator<XSSchema> iter = result.iterateSchema();
81 while (iter.hasNext()) {
82 XSSchema schema = iter.next();
83 if (URN_HL7_ORG_V2XML.equals(schema.getTargetNamespace())) {
84 parsePrimitives(schema, version);
85 parseComposites(schema, version);
86 }
87 }
88 }
89
90 private void parsePrimitives(XSSchema schema, Version version) throws Exception {
91 List<DatatypeDef> primitiveTypes = new ArrayList<>();
92 Iterator<XSType> types = schema.iterateTypes();
93
94 while (types.hasNext()) {
95 XSType type = types.next();
96 String dataTypeName = type.getName();
97 if (Arrays.binarySearch(PRIMITIVES, dataTypeName) >= 0)
98 primitiveTypes.add(new DatatypeDef(dataTypeName, dataTypeName));
99 }
100
101 Template template = VelocityFactory.getClasspathTemplateInstance(templatePackage + "/datatype_primitive.vsm");
102 String basePackageName = DefaultModelClassFactory.getVersionPackageName(version.getVersion());
103 String normalBasePackageName = DefaultModelClassFactory.getVersionPackageName(version.getVersion());
104
105 for (DatatypeDef def : primitiveTypes) {
106 String source = make(template, basePackageName, normalBasePackageName, def, version.getVersion());
107 if (source != null) {
108 writeFile(source, def, version);
109 }
110 }
111 }
112
113 private void parseComposites(XSSchema schema, Version version) throws Exception {
114 List<DatatypeDef> compositeTypes = new ArrayList<>();
115 Iterator<XSComplexType> types = schema.iterateComplexTypes();
116 while (types.hasNext()) {
117 XSComplexType complexType = types.next();
118 String dataTypeName = complexType.getName();
119
120
121 if (dataTypeName.startsWith("CE_")) dataTypeName = "CE";
122
123 if (isRealComposite(dataTypeName)) {
124 DatatypeDefDatatypeDef">DatatypeDef compositeType = new DatatypeDef(dataTypeName, dataTypeName);
125
126 XSParticle[] children = complexType
127 .getContentType()
128 .asParticle()
129 .getTerm()
130 .asModelGroup()
131 .getChildren();
132
133 for (int i = 0; i < children.length; i++) {
134 XSAttGroupDecl attrGroup = children[i]
135 .getTerm()
136 .asElementDecl()
137 .getType()
138 .asComplexType()
139 .getAttGroups().iterator().next();
140 String componentType = attrGroup.getAttributeUse("", "Type").getFixedValue().toString();
141 String componentDescription = attrGroup.getAttributeUse("", "LongName").getFixedValue().toString();
142 XSAttributeUse componentTable = attrGroup.getAttributeUse("", "Table");
143 int table = 0;
144 if (componentTable != null)
145 table = Integer.parseInt(componentTable.getFixedValue().toString().substring(3));
146
147 compositeType.addSubcomponentDef(
148 new DatatypeComponentDef(
149 dataTypeName,
150 i,
151 fixTypeName(dataTypeName, componentType),
152 componentDescription,
153 table));
154 }
155 compositeTypes.add(compositeType);
156 }
157
158 }
159
160 Template template = VelocityFactory.getClasspathTemplateInstance(templatePackage + "/datatype_composite.vsm");
161 String basePackageName = DefaultModelClassFactory.getVersionPackageName(version.getVersion());
162 String normalBasePackageName = DefaultModelClassFactory.getVersionPackageName(version.getVersion());
163
164 for (DatatypeDef def : compositeTypes) {
165 String source = make(template, basePackageName, normalBasePackageName, def, version.getVersion());
166 if (source != null) {
167 writeFile(source, def, version);
168 }
169 }
170 }
171
172
173 private static String fixTypeName(String parentName, String dataTypeName) {
174 if (dataTypeName.equals("ST") && parentName.equals("TS")) return "TSComponentOne";
175
176 if (dataTypeName.equals("varies")) return "Varies";
177
178
179 if (dataTypeName.equals("NUL")) return "NULLDT";
180 if (dataTypeName.equals("-")) return "NULLDT";
181
182 return dataTypeName;
183 }
184
185 private boolean isRealComposite(String dataTypeName) {
186 return Arrays.binarySearch(PRIMITIVES, dataTypeName) < 0 &&
187 Arrays.binarySearch(EXCLUDE_COMPOSITES, dataTypeName) < 0 &&
188 dataTypeName.indexOf('.') < 0;
189 }
190
191 private void writeFile(String source, DatatypeDef def, Version version) throws IOException {
192
193 String dirName = String.format("%s/ca/uhn/hl7v2/model/%s/datatype/", targetDirectory, version.getPackageVersion());
194 File dir = new File(dirName);
195 if (!dir.exists()) {
196 dir.mkdirs();
197 }
198 String targetFile = String.format("%s/%s.java", dirName, def.getType());
199
200 try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(targetFile, false), StandardCharsets.UTF_8))) {
201 writer.write(source);
202 writer.flush();
203 }
204 }
205
206 private String make(Template template, String basePackageName, String normalBasePackageName,
207 DatatypeDef def, String version) {
208 StringWriter out = new StringWriter();
209 Context ctx = new VelocityContext();
210 ctx.put("datatype", def);
211 ctx.put("datatypeName", def.getType());
212 ctx.put("version", version);
213 ctx.put("basePackageName", basePackageName);
214 ctx.put("normalBasePackageName", normalBasePackageName);
215 ctx.put("components", def.getSubComponentDefs());
216 ctx.put("desc", def.getName());
217
218 template.merge(ctx, out);
219 return out.toString();
220 }
221
222
223 public static void main(String... args) {
224 try {
225 XsdDataTypeGeneratortor.html#XsdDataTypeGenerator">XsdDataTypeGenerator xdtg = new XsdDataTypeGenerator("C:/temp", "/ca.uhn.hl7v2.sourcegen.templates");
226 long start = System.currentTimeMillis();
227 for (Version version : Version.values()) {
228 System.out.println("Creating data types for " + version);
229 xdtg.parse(version);
230 }
231 System.out.println("Done in " + (System.currentTimeMillis() - start) + " ms.");
232 } catch (Exception e) {
233 e.printStackTrace();
234 }
235 }
236 }