1 package ca.uhn.hl7v2.mvnplugin;
2
3 import java.io.File;
4 import java.io.FileReader;
5 import java.io.FileWriter;
6 import java.io.StringWriter;
7 import java.util.ArrayList;
8 import java.util.Arrays;
9 import java.util.HashMap;
10 import java.util.HashSet;
11 import java.util.List;
12 import java.util.Map;
13 import java.util.Set;
14 import java.util.TreeMap;
15
16 import org.apache.commons.lang.StringUtils;
17 import org.apache.maven.model.Resource;
18 import org.apache.maven.plugin.AbstractMojo;
19 import org.apache.maven.plugin.MojoExecutionException;
20 import org.apache.maven.plugin.MojoFailureException;
21 import org.apache.maven.project.MavenProject;
22 import org.apache.velocity.Template;
23 import org.apache.velocity.VelocityContext;
24 import org.apache.velocity.tools.generic.EscapeTool;
25 import org.codehaus.plexus.util.IOUtil;
26
27 import ca.uhn.hl7v2.VersionLogger;
28 import ca.uhn.hl7v2.conf.ProfileException;
29 import ca.uhn.hl7v2.conf.parser.ProfileParser;
30 import ca.uhn.hl7v2.conf.spec.RuntimeProfile;
31 import ca.uhn.hl7v2.conf.spec.message.AbstractSegmentContainer;
32 import ca.uhn.hl7v2.conf.spec.message.Component;
33 import ca.uhn.hl7v2.conf.spec.message.Field;
34 import ca.uhn.hl7v2.conf.spec.message.ProfileStructure;
35 import ca.uhn.hl7v2.conf.spec.message.Seg;
36 import ca.uhn.hl7v2.conf.spec.message.SegGroup;
37 import ca.uhn.hl7v2.conf.spec.message.StaticDef;
38 import ca.uhn.hl7v2.conf.spec.message.SubComponent;
39 import ca.uhn.hl7v2.sourcegen.util.VelocityFactory;
40 import ca.uhn.hl7v2.util.XMLUtils;
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 public class XsdConfGenMojo extends AbstractMojo {
64
65 private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XsdConfGenMojo.class);
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87 private List<String> profiles;
88
89
90
91
92
93
94
95
96
97 private MavenProject project;
98
99
100
101
102
103
104
105
106 private String targetDirectory;
107
108
109
110
111
112
113
114
115
116
117 private final boolean filterBogusGroups = true;
118
119
120
121
122
123
124
125
126
127 private String targetFile;
128
129
130
131
132
133
134
135
136
137 private boolean constrain = false;
138
139
140
141
142
143
144
145
146
147
148
149
150
151 private Map<String, String> linkTriggerToStructure;
152
153 private String templatePackage = "ca.uhn.hl7v2.sourcegen.templates.xsd";
154
155 private static final Set<String> ourConstrainedUsageTypes = new HashSet<>(new ArrayList<>(Arrays.asList("R", "RE", "O", "C")));
156
157
158
159
160 public void execute() throws MojoExecutionException {
161
162 try {
163
164 if (!new File(targetDirectory).exists()) {
165 ourLog.info("Creating directory: {}", targetDirectory);
166 new File(targetDirectory).mkdirs();
167 }
168
169 List<RuntimeProfile> parsedProfiles = new ArrayList<>();
170 for (String nextProfile : profiles) {
171
172 ourLog.info("Reading profile: {}", nextProfile);
173 FileReader reader = new FileReader(nextProfile);
174 String profileString = IOUtil.toString(reader);
175
176 ProfileParser profileParser = new ProfileParser(false);
177 RuntimeProfile runtimeProfile = profileParser.parse(profileString);
178
179 if (constrain) {
180 for (int i = 0; i < runtimeProfile.getMessage().getChildrenAsList().size(); i++) {
181 ProfileStructure next = runtimeProfile.getMessage().getChildrenAsList().get(i);
182 if (!ourConstrainedUsageTypes.contains(next.getUsage())) {
183 runtimeProfile.getMessage().getChildrenAsList().remove(i);
184 i--;
185 } else {
186 if (next instanceof Seg) {
187 constrainSeg((Seg) next);
188 } else {
189 constrainSegGroup((SegGroup) next);
190 }
191 }
192 }
193 }
194
195 if (filterBogusGroups) {
196 StaticDef staticDef = runtimeProfile.getMessage();
197 filterBogusGroups(staticDef);
198 }
199
200 parsedProfiles.add(runtimeProfile);
201 }
202
203 if (linkTriggerToStructure == null) {
204 linkTriggerToStructure = new HashMap<>();
205 }
206
207 linkTriggerToStructure = new TreeMap<>(linkTriggerToStructure);
208
209 VelocityContext ctx = new VelocityContext();
210 ctx.put("runtimeProfiles", parsedProfiles);
211 ctx.put("hapiVersion", StringUtils.defaultString(VersionLogger.getVersion(), "X.X"));
212 ctx.put("segmentDefs", new HashSet<String>());
213 ctx.put("fieldDefs", new HashSet<String>());
214 ctx.put("esc", new EscapeTool());
215 ctx.put("compositeFieldDefs", new HashSet<String>());
216 ctx.put("triggerMappings", linkTriggerToStructure);
217
218 Template template = VelocityFactory.getClasspathTemplateInstance(templatePackage.replace('.', '/') + "/message_xml_its.vm");
219
220 File targetFileDef = new File(targetDirectory, targetFile);
221 ourLog.info("Generating: {}", targetFileDef.getAbsolutePath());
222
223 StringWriter sw = new StringWriter();
224 template.merge(ctx, sw);
225 sw.close();
226
227
228
229
230
231 if (ourLog.isDebugEnabled()) {
232 ourLog.debug("DOcument: " + sw.toString());
233 }
234
235 String xml = XMLUtils.serialize(XMLUtils.parse(sw.toString()), true);
236
237 FileWriter w = new FileWriter(targetFileDef, false);
238 w.write(xml);
239 w.close();
240
241 } catch (Exception e) {
242 throw new MojoExecutionException(e.getMessage(), e);
243 }
244
245 if (project != null) {
246 Resource resource = new Resource();
247 resource.setDirectory(targetDirectory);
248 project.addResource(resource);
249
250 }
251
252 }
253
254 private void filterBogusGroups(AbstractSegmentContainer theParent) {
255 List<ProfileStructure> children = theParent.getChildrenAsList();
256
257 for (int childIndex = 0; childIndex < children.size(); childIndex++) {
258 ProfileStructure nextChild = children.get(childIndex);
259 if (nextChild instanceof SegGroup) {
260 SegGroup nextChildSg = (SegGroup) nextChild;
261 if (nextChildSg.getChildren() == 1 && nextChildSg.getChild(1) instanceof SegGroup) {
262 SegGroup newNextChildSg = (SegGroup) nextChildSg.getChild(1);
263 ourLog.info("Replacing bogus group {} with {}", newNextChildSg.toString(), nextChildSg.toString());
264 nextChildSg = newNextChildSg;
265 children.set(childIndex, nextChildSg);
266 }
267
268 filterBogusGroups(nextChildSg);
269 }
270 }
271
272 }
273
274 private void constrainSegGroup(SegGroup theNext) throws ProfileException {
275 for (int i = 0; i < theNext.getChildrenAsList().size(); i++) {
276 ProfileStructure next = theNext.getChildrenAsList().get(i);
277 if (!ourConstrainedUsageTypes.contains(next.getUsage())) {
278 theNext.getChildrenAsList().remove(i);
279 i--;
280 } else {
281 if (next instanceof Seg) {
282 constrainSeg((Seg) next);
283 } else {
284 constrainSegGroup((SegGroup) next);
285 }
286 }
287 }
288 }
289
290 private void constrainSeg(Seg theNext) throws ProfileException {
291 for (int i = 0; i < theNext.getFieldsAsList().size(); i++) {
292 Field next = theNext.getFieldsAsList().get(i);
293 if (!ourConstrainedUsageTypes.contains(next.getUsage())) {
294 Field unsupField = new Field();
295 unsupField.setDatatype("ST");
296 unsupField.setDescription("Unsupported");
297 unsupField.setMax((short) 0);
298 unsupField.setMin((short) 0);
299 unsupField.setName("Unsupported");
300 unsupField.setUsage("X");
301 theNext.getFieldsAsList().set(i, unsupField);
302 } else {
303 for (int j = 0; j < next.getChildrenAsList().size(); j++) {
304 Component nextComponent = next.getChildrenAsList().get(j);
305 if (!ourConstrainedUsageTypes.contains(nextComponent.getUsage())) {
306 nextComponent.setName("Unsupported");
307 nextComponent.setDescription("Unsupported");
308 for (SubComponent nextSub : nextComponent.getChildrenAsList()) {
309 nextSub.setName("Unsupported");
310 nextSub.setDescription("Unsupported");
311 }
312 } else {
313 for (SubComponent nextSub : nextComponent.getChildrenAsList()) {
314 if (!ourConstrainedUsageTypes.contains(nextSub.getUsage())) {
315 nextSub.setName("Unsupported");
316 nextSub.setDescription("Unsupported");
317 }
318 }
319 }
320 }
321 }
322 }
323 }
324
325 public static void main(String[] args) throws MojoExecutionException, MojoFailureException {
326
327 XsdConfGenMojo tst;
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344 tst = new XsdConfGenMojo();
345 tst.targetDirectory = "hapi-test/target/generated-sources/confgen";
346 tst.targetFile = "CGTA_INPUT_HL7V2.xsd";
347 tst.profiles = new ArrayList<>();
348 tst.linkTriggerToStructure = new HashMap<>();
349
350 tst.profiles.add("/eclipse/workspace/CGTA_Input_Tester_gc/ConverterLibrary/src/main/resources/ca/cgta/input/conf/cgta-adt_a01.xml");
351 tst.linkTriggerToStructure.put("ADT_A02", "ADT_A01");
352 tst.linkTriggerToStructure.put("ADT_A03", "ADT_A01");
353 tst.linkTriggerToStructure.put("ADT_A04", "ADT_A01");
354 tst.linkTriggerToStructure.put("ADT_A05", "ADT_A01");
355 tst.linkTriggerToStructure.put("ADT_A06", "ADT_A01");
356 tst.linkTriggerToStructure.put("ADT_A07", "ADT_A01");
357 tst.linkTriggerToStructure.put("ADT_A08", "ADT_A01");
358 tst.linkTriggerToStructure.put("ADT_A10", "ADT_A01");
359 tst.linkTriggerToStructure.put("ADT_A11", "ADT_A01");
360 tst.linkTriggerToStructure.put("ADT_A13", "ADT_A01");
361 tst.linkTriggerToStructure.put("ADT_A28", "ADT_A01");
362 tst.linkTriggerToStructure.put("ADT_A31", "ADT_A01");
363 tst.linkTriggerToStructure.put("ADT_A37", "ADT_A01");
364 tst.linkTriggerToStructure.put("ADT_A40", "ADT_A01");
365 tst.linkTriggerToStructure.put("ADT_A42", "ADT_A01");
366 tst.linkTriggerToStructure.put("ADT_A45", "ADT_A01");
367 tst.linkTriggerToStructure.put("ADT_A60", "ADT_A01");
368
369 tst.profiles.add("/eclipse/workspace//CGTA_Input_Tester_gc/ConverterLibrary/src/main/resources/ca/cgta/input/conf/cgta-adt_a17_a37.xml");
370 tst.linkTriggerToStructure.put("ADT_A37", "ADT_A17");
371
372 tst.profiles.add("/eclipse/workspace//CGTA_Input_Tester_gc/ConverterLibrary/src/main/resources/ca/cgta/input/conf/cgta-oru_r01.xml");
373
374 tst.profiles.add("/eclipse/workspace//CGTA_Input_Tester_gc/ConverterLibrary/src/main/resources/ca/cgta/input/conf/cgta-rde_o11.xml");
375
376 tst.profiles.add("/eclipse/workspace//CGTA_Input_Tester_gc/ConverterLibrary/src/main/resources/ca/cgta/input/conf/cgta-ras_o17.xml");
377
378 tst.templatePackage = "ca.uhn.hl7v2.sourcegen.templates.xsd";
379
380 tst.constrain = true;
381 tst.execute();
382
383 }
384
385 }