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
28
29 package ca.uhn.hl7v2.sourcegen;
30
31 import java.io.BufferedWriter;
32 import java.io.File;
33 import java.io.FileOutputStream;
34 import java.io.IOException;
35 import java.io.OutputStreamWriter;
36 import java.io.StringWriter;
37 import java.sql.Connection;
38 import java.sql.ResultSet;
39 import java.sql.SQLException;
40 import java.sql.Statement;
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 import java.util.HashSet;
44 import java.util.Set;
45
46 import org.apache.velocity.Template;
47 import org.apache.velocity.VelocityContext;
48 import org.apache.velocity.context.Context;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52 import ca.uhn.hl7v2.HL7Exception;
53 import ca.uhn.hl7v2.database.NormativeDatabase;
54 import ca.uhn.hl7v2.model.DataTypeException;
55 import ca.uhn.hl7v2.parser.DefaultModelClassFactory;
56 import ca.uhn.hl7v2.sourcegen.util.VelocityFactory;
57
58
59
60
61
62
63
64
65 public class DataTypeGenerator {
66
67 private static final Logger log = LoggerFactory.getLogger(DataTypeGenerator.class);
68 private static boolean ourMakeAll;
69
70
71
72
73
74
75
76 public static void makeAll(String baseDirectory, String version, String theTemplatePackage, String theFileExt) throws IOException, SQLException, HL7Exception {
77
78 if (!(baseDirectory.endsWith("\\") || baseDirectory.endsWith("/"))) {
79 baseDirectory = baseDirectory + "/";
80 }
81 File targetDir = SourceGenerator.makeDirectory(baseDirectory + DefaultModelClassFactory.getVersionPackagePath(version) + "datatype");
82
83
84
85 ArrayList<String> types = getDataTypes(version);
86
87 System.out.println("Generating " + types.size() + " datatypes for version " + version);
88 if (types.size() == 0) {
89 log.warn("No version {} data types found in database {}",
90 version, System.getProperty("ca.on.uhn.hl7.database.url"));
91 }
92
93 for (String type : types) {
94 try {
95 String basePackage = DefaultModelClassFactory.getVersionPackageName(version);
96
97 String hapiTestGenType = System.getProperty("hapi.test.gentype");
98 if (hapiTestGenType != null && !hapiTestGenType.contains(type)) {
99 continue;
100 }
101
102 make(targetDir, type, version, basePackage, theTemplatePackage, theFileExt);
103 } catch (DataTypeException dte) {
104 log.warn("{} - {}", dte.getClass().getName(), dte.getMessage());
105 } catch (Exception e) {
106 log.error("Error creating source code for all data types", e);
107 }
108 }
109 }
110
111 public static ArrayList<String> getDataTypes(String version) throws SQLException {
112 ArrayList<String> types = new ArrayList<>();
113 NormativeDatabase normativeDatabase = NormativeDatabase.getInstance();
114 Connection conn = normativeDatabase.getConnection();
115 Statement stmt = conn.createStatement();
116
117 ResultSet rs = stmt.executeQuery("select data_type_code from HL7DataTypes, HL7Versions where HL7Versions.version_id = HL7DataTypes.version_id and HL7Versions.hl7_version = '" + version + "'");
118 while (rs.next()) {
119 types.add(rs.getString(1));
120 }
121
122
123
124
125 rs = stmt.executeQuery("select data_structure from HL7DataStructures, HL7Versions where (" +
126 "data_type_code = 'CF' or " +
127 "data_type_code = 'CK' or " +
128 "data_type_code = 'CM' or " +
129 "data_type_code = 'CN' or " +
130 "data_type_code = 'CQ') and " +
131 "HL7Versions.version_id = HL7DataStructures.version_id and HL7Versions.hl7_version = '" + version + "'");
132 while (rs.next()) {
133 String string = rs.getString(1);
134 if (string.equals("-")) {
135 continue;
136 }
137
138 types.add(string);
139 }
140
141 stmt.close();
142 normativeDatabase.returnConnection(conn);
143 return types;
144 }
145
146
147
148
149
150
151
152
153
154 public static void make(File targetDirectory, String dataType, String version, String basePackage, String theTemplatePackage, String theFileExt) throws Exception {
155
156 if (!targetDirectory.isDirectory()) throw new IOException("Can't create file in " +
157 targetDirectory.toString() + " - it is not a directory.");
158
159
160 NormativeDatabase normativeDatabase = NormativeDatabase.getInstance();
161 Connection conn = normativeDatabase.getConnection();
162 Statement stmt = conn.createStatement();
163
164
165 String sql = "SELECT HL7DataStructures.data_structure, HL7DataStructureComponents.seq_no, HL7DataStructures.description, HL7DataStructureComponents.table_id, " +
166 "HL7Components.description, HL7Components.table_id, HL7Components.data_type_code, HL7Components.data_structure " +
167 "FROM HL7Versions LEFT JOIN (HL7DataStructures LEFT JOIN (HL7DataStructureComponents LEFT JOIN HL7Components " +
168 "ON HL7DataStructureComponents.comp_no = HL7Components.comp_no AND " +
169 "HL7DataStructureComponents.version_id = HL7Components.version_id) " +
170 "ON HL7DataStructures.version_id = HL7DataStructureComponents.version_id " +
171 "AND HL7DataStructures.data_structure = HL7DataStructureComponents.data_structure) " +
172 "ON HL7DataStructures.version_id = HL7Versions.version_id " +
173 "WHERE HL7DataStructures.data_structure = '" +
174 dataType +
175 "' AND HL7Versions.hl7_version = '" +
176 version +
177 "' ORDER BY HL7DataStructureComponents.seq_no";
178 ResultSet rs = stmt.executeQuery(sql);
179
180 ArrayList<String> dataTypes = new ArrayList<>(20);
181 ArrayList<String> descriptions = new ArrayList<>(20);
182 ArrayList<Integer> tables = new ArrayList<>(20);
183 String description = null;
184 while (rs.next()) {
185 if (description == null) description = rs.getString(3);
186
187 String de = rs.getString(5);
188 String dt = rs.getString(8);
189 int ta = rs.getInt(4);
190
191 if (dt != null) if (dt.startsWith("CE")) dt = "CE";
192
193
194
195
196
197 if (dataType.equals("TS") && "ST".equals(dt) && dataTypes.isEmpty()) {
198 dt = "TSComponentOne";
199 }
200
201 dataTypes.add(dt);
202 descriptions.add(de);
203 tables.add(ta);
204 }
205 stmt.close();
206 normativeDatabase.returnConnection(conn);
207
208
209 String source;
210 if (dataTypes.size() == 1) {
211 if (ourMakeAll || dataType.equals("FT") || dataType.equals("ST") || dataType.equals("TX")
212 || dataType.equals("NM") || dataType.equals("SI") || dataType.equals("TN")
213 || dataType.equals("GTS")) {
214 source = makePrimitive(new DatatypeDef(dataType, description), version, basePackage, theTemplatePackage);
215 } else {
216 source = null;
217 }
218 } else if (dataTypes.size() > 1) {
219 int numComponents = dataTypes.size();
220
221 String[] type = new String[numComponents];
222 String[] desc = new String[numComponents];
223 int[] table = new int[numComponents];
224 DatatypeComponentDeftatypeComponentDef">DatatypeComponentDef[] componentDefs = new DatatypeComponentDef[numComponents];
225 Set<String> names = new HashSet<>();
226 for (int i = 0; i < numComponents; i++) {
227 type[i] = dataTypes.get(i);
228 String componentName = descriptions.get(i);
229
230 if (names.contains(componentName)) {
231 for (int j = 2; ; j++) {
232 if (!names.contains(componentName + j)) {
233 componentName = componentName + j;
234 break;
235 }
236 }
237 }
238 names.add(componentName);
239
240 desc[i] = componentName;
241 table[i] = tables.get(i);
242
243 String typeName = dataTypes.get(i);
244 typeName = SourceGenerator.getAlternateType(typeName, version);
245
246 componentDefs[i] = new DatatypeComponentDef(dataType, i, typeName, componentName, tables.get(i));
247 }
248
249 source = makeComposite(dataType, description, componentDefs, type, desc, table, version, basePackage, theTemplatePackage);
250 } else {
251 if (dataType.equals("var")) {
252 return;
253 }
254
255
256 throw new DataTypeException("The data type " + dataType + " could not be found");
257 }
258
259
260
261
262 if (source != null) {
263 String targetFile = targetDirectory.toString() + "/" + dataType + "." + theFileExt;
264 try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(targetFile, false), SourceGenerator.ENCODING))) {
265 writer.write(source);
266 writer.flush();
267 }
268 }
269 }
270
271
272
273
274
275
276 private static String makePrimitive(DatatypeDef theDatatype, String version, String basePackage, String theTemplatePackage) throws Exception {
277
278 StringWriter out = new StringWriter();
279
280 theTemplatePackage = theTemplatePackage.replace(".", "/");
281 Template template = VelocityFactory.getClasspathTemplateInstance(theTemplatePackage + "/datatype_primitive.vsm");
282 Context ctx = new VelocityContext();
283 ctx.put("datatype", theDatatype);
284 ctx.put("version", version);
285 ctx.put("basePackageName", basePackage);
286 ctx.put("normalBasePackageName", DefaultModelClassFactory.getVersionPackageName(version));
287
288 template.merge(ctx, out);
289 return out.toString();
290
291 }
292
293
294
295
296
297
298 private static String makeComposite(String dataType, String description, DatatypeComponentDef[] componentDefs, String[] dataTypes,
299 String[] descriptions, int[] tables, String version, String basePackage, String theTemplatePackage) throws Exception {
300
301 StringWriter out = new StringWriter();
302
303 for (DatatypeComponentDef componentDef : componentDefs) {
304 if (componentDef.getType().equals(dataType)) {
305 log.warn("Datatype {} has a component child also of type {}! Can not recurse like this", dataType, dataType);
306 componentDef.setType("ST");
307 }
308 }
309
310 for (int i = 0; i < dataTypes.length; i++) {
311 if (dataTypes[i].equals(dataType)) {
312 log.warn("Datatype {} has a child also of type {}! Can not recurse like this", dataType, dataType);
313 dataTypes[i] = "ST";
314 }
315 }
316
317 theTemplatePackage = theTemplatePackage.replace(".", "/");
318 Template template = VelocityFactory.getClasspathTemplateInstance(theTemplatePackage + "/datatype_composite.vsm");
319 Context ctx = new VelocityContext();
320 ctx.put("datatypeName", dataType);
321 ctx.put("version", version);
322 ctx.put("basePackageName", basePackage);
323 ctx.put("components", Arrays.asList(componentDefs));
324 ctx.put("desc", description);
325
326 template.merge(ctx, out);
327 return out.toString();
328
329 }
330
331
332 public static void main(String[] args) {
333
334 try {
335 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
336
337
338
339 makeAll("c:/testsourcegen", "2.5", "", "java");
340 } catch (Exception e) {
341 e.printStackTrace();
342 }
343
344
345
346
347
348
349
350 }
351
352 public static void writeDatatype(String theFileName, String theVersion, DatatypeDef theFieldDef, String theBasePackage, String theTemplatePackage) throws Exception {
353
354 String text;
355 if (theFieldDef.getSubComponentDefs().isEmpty()) {
356 text = makePrimitive(theFieldDef, theVersion, theBasePackage, theTemplatePackage);
357 } else {
358 text = makeComposite(theFieldDef.getType(), theFieldDef.getName(), theFieldDef.getSubComponentDefs().toArray(new DatatypeComponentDef[0]), null, null, null, theVersion, theBasePackage, theTemplatePackage);
359 }
360
361 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(theFileName, false), SourceGenerator.ENCODING));
362 writer.write(text);
363 writer.flush();
364 writer.close();
365
366 }
367
368
369
370
371
372 public static void setMakeAll(boolean theMakeAll) {
373 ourMakeAll = theMakeAll;
374 }
375
376 }