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.BufferedWriter;
30 import java.io.File;
31 import java.io.FileOutputStream;
32 import java.io.IOException;
33 import java.io.OutputStreamWriter;
34 import java.sql.Connection;
35 import java.sql.ResultSet;
36 import java.sql.SQLException;
37 import java.sql.Statement;
38 import java.util.ArrayList;
39 import java.util.Collections;
40 import java.util.HashSet;
41 import java.util.List;
42 import java.util.Set;
43
44 import org.apache.maven.plugin.MojoExecutionException;
45 import org.apache.maven.plugin.MojoFailureException;
46 import org.apache.velocity.Template;
47 import org.apache.velocity.VelocityContext;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50
51 import ca.uhn.hl7v2.HL7Exception;
52 import ca.uhn.hl7v2.database.NormativeDatabase;
53 import ca.uhn.hl7v2.parser.DefaultModelClassFactory;
54 import ca.uhn.hl7v2.sourcegen.util.VelocityFactory;
55
56
57
58
59
60
61
62
63 public class SegmentGenerator {
64
65 private static final Logger log = LoggerFactory.getLogger(SegmentGenerator.class);
66
67
68
69
70
71 public static void makeAll(String baseDirectory, String version, String theTemplatePackage, String theFileExt) throws IOException, SQLException, HL7Exception, MojoExecutionException {
72
73 if (!(baseDirectory.endsWith("\\") || baseDirectory.endsWith("/"))) {
74 baseDirectory = baseDirectory + "/";
75 }
76 File targetDir = SourceGenerator.makeDirectory(baseDirectory + DefaultModelClassFactory.getVersionPackagePath(version) + "segment");
77
78 ArrayList<String> segments = getSegmentNames(version);
79
80 if (segments.size() == 0) {
81 log.warn("No version {} segments found in database {}",
82 version, System.getProperty("ca.on.uhn.hl7.database.url"));
83 }
84
85 for (String segment : segments) {
86 try {
87
88 String hapiTestGenSegment = System.getProperty("hapi.test.gensegment");
89 if (hapiTestGenSegment != null && !hapiTestGenSegment.contains(segment)) {
90 continue;
91 }
92
93 makeSegment(segment, version, theTemplatePackage, targetDir, theFileExt);
94 } catch (Exception e) {
95
96
97 throw new MojoExecutionException("Failure generating segments", e);
98 }
99 }
100 }
101
102 public static ArrayList<String> getSegmentNames(String version) throws SQLException {
103
104 NormativeDatabase normativeDatabase = NormativeDatabase.getInstance();
105 Connection conn = normativeDatabase.getConnection();
106 Statement stmt = conn.createStatement();
107 String sql = "SELECT seg_code, section from HL7Segments, HL7Versions where HL7Segments.version_id = HL7Versions.version_id AND hl7_version = '" + version + "'";
108
109 ResultSet rs = stmt.executeQuery(sql);
110
111 ArrayList<String> segments = new ArrayList<>();
112 while (rs.next()) {
113 String segName = rs.getString(1);
114
115
116 if ("ED".equals(segName)) {
117 continue;
118 }
119
120 if (Character.isLetter(segName.charAt(0))) {
121 segments.add(altSegName(segName));
122 }
123 }
124 stmt.close();
125 normativeDatabase.returnConnection(conn);
126 return segments;
127 }
128
129
130
131
132
133
134
135 public static String altSegName(String segmentName) {
136 String ret = segmentName;
137 if (ret.equals("Z..")) {
138 ret = "Z";
139 }
140 if (ret.equals("CON")) {
141 ret = "CON_";
142 }
143 return ret;
144 }
145
146
147
148
149 public static void makeSegment(String name, String version, String theTemplatePackage, File theTargetDir, String theFileExt) throws Exception {
150
151 ArrayList<SegmentElement> elements = new ArrayList<>();
152 String segDesc = null;
153 SegmentElement se;
154
155 NormativeDatabase normativeDatabase = NormativeDatabase.getInstance();
156 try {
157 Connection conn = normativeDatabase.getConnection();
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177 listTables(conn, "HL7SegmentDataElements");
178 listTables(conn, "HL7DataElements");
179 listTables(conn, "HL7Segments");
180
181
182 String lengthColName;
183 if (version.startsWith("2.7") || version.startsWith("2.8")) {
184 lengthColName = "HL7DataElements.max_length";
185 } else {
186 lengthColName = "HL7DataElements.length";
187 }
188
189 StringBuilder sql = new StringBuilder();
190 sql.append("SELECT ");
191
192
193
194 sql.append("HL7SegmentDataElements.seg_code, HL7SegmentDataElements.seq_no, ");
195 sql.append("HL7SegmentDataElements.repetitional, HL7SegmentDataElements.repetitions, ");
196 sql.append("HL7DataElements.description, ").append(lengthColName).append(", HL7DataElements.table_id, ");
197 sql.append("HL7SegmentDataElements.req_opt, HL7Segments.description, HL7DataElements.data_structure ");
198 sql.append("FROM HL7Versions RIGHT JOIN (HL7Segments INNER JOIN (HL7DataElements INNER JOIN HL7SegmentDataElements ");
199 sql.append("ON (HL7DataElements.version_id = HL7SegmentDataElements.version_id) ");
200 sql.append("AND (HL7DataElements.data_item = HL7SegmentDataElements.data_item)) ");
201 sql.append("ON (HL7Segments.version_id = HL7SegmentDataElements.version_id) ");
202 sql.append("AND (HL7Segments.seg_code = HL7SegmentDataElements.seg_code)) ");
203 sql.append("ON (HL7Versions.version_id = HL7Segments.version_id) ");
204 sql.append("WHERE ");
205 sql.append("HL7SegmentDataElements.seg_code = '");
206 sql.append(name);
207 sql.append("' and HL7Versions.hl7_version = '");
208 sql.append(version);
209 sql.append("' ");
210 sql.append("ORDER BY HL7SegmentDataElements.seg_code, HL7SegmentDataElements.seq_no;");
211
212
213 Statement stmt;
214 ResultSet rs;
215 try {
216 stmt = conn.createStatement();
217 rs = stmt.executeQuery(sql.toString());
218 } catch (Exception e) {
219 throw new MojoFailureException("Failed to execute the following SQL: " + sql.toString(), e);
220 }
221 List<String> usedFieldDescs = new ArrayList<>();
222 int index = 0;
223 while (rs.next()) {
224 if (segDesc == null) {
225 segDesc = rs.getString(9);
226 }
227 se = new SegmentElement(name, version, index++);
228 se.field = rs.getInt(2);
229 se.rep = rs.getString(3);
230 se.repetitions = rs.getInt(4);
231 if (se.repetitions == 0) {
232 if (se.rep == null || !se.rep.equalsIgnoreCase("Y")) {
233 se.repetitions = 1;
234 }
235 }
236 se.desc = rs.getString(5);
237
238
239 String originalSeDesc = se.desc;
240 if (usedFieldDescs.contains(se.desc)) {
241 se.desc = se.desc + " Number " + (Collections.frequency(usedFieldDescs, originalSeDesc) + 1);
242 }
243 usedFieldDescs.add(originalSeDesc);
244
245 se.length = rs.getInt(6);
246 se.table = rs.getInt(7);
247 se.opt = rs.getString(8);
248 se.type = rs.getString(10);
249
250 if (se.type.startsWith("CE")) {
251 se.type = "CE";
252 }
253
254
255 if (se.type.equals("-") || se.type.equals("NUL")) {
256 se.type = "NULLDT";
257 }
258
259
260
261
262
263
264
265
266 if (version.equals("2.3") && name.equals("MRG") && index == 7) {
267 se.type = "XPN";
268 }
269
270
271 if (version.equals("2.3") && name.equals("ORC") && index == 14) {
272 se.type = "XTN";
273 }
274
275
276 if (version.equals("2.3") && name.equals("PID") && index == 5) {
277 se.rep = "Y";
278 se.repetitions = -1;
279 }
280
281 elements.add(se);
282
283
284
285 }
286 stmt.close();
287 normativeDatabase.returnConnection(conn);
288 } catch (SQLException sqle) {
289
290
291 throw new MojoFailureException("Failed to generate segment", sqle);
292 }
293
294 String fileName = theTargetDir.toString() + "/" + name + "." + theFileExt;
295
296 String basePackageName = DefaultModelClassFactory.getVersionPackageName(version);
297 String[] datatypePackages = { basePackageName + "datatype" };
298 writeSegment(fileName, version, name, elements, segDesc, basePackageName, datatypePackages, theTemplatePackage);
299
300 }
301
302 private static void listTables(Connection conn, String tableName) throws MojoFailureException, SQLException {
303 {
304 StringBuilder sql = new StringBuilder();
305 sql.append("SELECT ");
306 sql.append(tableName).append(".* ");
307 sql.append("FROM ").append(tableName).append(" ");
308
309
310 Statement stmt;
311 ResultSet rs;
312 try {
313 stmt = conn.createStatement();
314 rs = stmt.executeQuery(sql.toString());
315 } catch (Exception e) {
316 throw new MojoFailureException("Failed to execute the following SQL: " + sql.toString(), e);
317 }
318
319 rs.next();
320 Set<String> cols = new HashSet<>();
321 for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
322 cols.add(rs.getMetaData().getColumnName(i+1));
323 }
324
325
326
327
328 rs.close();
329 stmt.close();
330 }
331
332
333 }
334
335
336
337 public static void writeSegment(String fileName, String version, String segmentName, ArrayList<SegmentElement> elements, String description, String basePackage, String[] datatypePackages, String theTemplatePackage) throws Exception {
338 log.debug("Writing segment: {}", fileName);
339
340 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName, false), SourceGenerator.ENCODING));
341
342 theTemplatePackage = theTemplatePackage.replace(".", "/");
343 Template template = VelocityFactory.getClasspathTemplateInstance(theTemplatePackage + "/segment.vsm");
344 VelocityContext ctx = new VelocityContext();
345 ctx.put("segmentName", segmentName);
346 ctx.put("typeDescription", description);
347 ctx.put("basePackageName", basePackage);
348 ctx.put("elements", elements);
349 ctx.put("datatypePackages", datatypePackages);
350 ctx.put("hl7VersionInQuotes", '"' + version + '"');
351
352 template.merge(ctx, out);
353
354
355
356
357 out.flush();
358 out.close();
359 }
360
361
362 }