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.*;
33
34 import ca.uhn.hl7v2.Version;
35 import ca.uhn.hl7v2.parser.DefaultModelClassFactory;
36 import ca.uhn.hl7v2.sourcegen.util.VelocityFactory;
37 import com.sun.xml.xsom.*;
38 import com.sun.xml.xsom.parser.XSOMParser;
39 import org.apache.velocity.Template;
40 import org.apache.velocity.VelocityContext;
41 import org.apache.velocity.context.Context;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45
46
47
48
49
50
51
52
53
54 public class XsdMessageGenerator {
55
56 private static final Logger LOG = LoggerFactory.getLogger(XsdMessageGenerator.class);
57 public static final String URN_HL7_ORG_V2XML = "urn:hl7-org:v2xml";
58
59 private final String templatePackage;
60 private final String targetDirectory;
61 private Template messageTemplate;
62 private Template groupTemplate;
63
64
65 public XsdMessageGenerator(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 " + dir + " - it is not a directory.");
69 this.targetDirectory = dir;
70 this.templatePackage = templatePackage.replace(".", "/");
71 }
72
73 public void parse(Version version) throws Exception {
74 messageTemplate = VelocityFactory.getClasspathTemplateInstance(templatePackage + "/messages.vsm");
75 groupTemplate = VelocityFactory.getClasspathTemplateInstance(templatePackage + "/group.vsm");
76 XSOMParser parser = new XSOMParser();
77 String dir = String.format("/hl7v2xsd/%s/messages.xsd", version.getVersion());
78 URL url = getClass().getResource(dir);
79 parser.setErrorHandler(new SimpleErrorHandler());
80 parser.parse(url);
81 XSSchemaSet result = parser.getResult();
82 Iterator<XSSchema> iter = result.iterateSchema();
83 while (iter.hasNext()) {
84 XSSchema schema = iter.next();
85 if (URN_HL7_ORG_V2XML.equals(schema.getTargetNamespace())) {
86 parseMessages(schema, version);
87 }
88 }
89 }
90
91
92
93
94
95
96
97
98
99
100
101 private void parseMessages(XSSchema schema, Version version) throws Exception {
102
103 String basePackageName = DefaultModelClassFactory.getVersionPackageName(version.getVersion());
104
105 XSModelGroupDecl allMessages = schema.getModelGroupDecl("ALLMESSAGES.CONTENT");
106 XSParticle[] messages = allMessages.getModelGroup().getChildren();
107 for (XSParticle message : messages) {
108 XSElementDecl messageElement = message.getTerm().asElementDecl();
109 GroupDef messageDef = parseGroupOrMessage(messageElement.getName(), message, true, version, basePackageName, new HashMap<>());
110 String messageClass = makeMessage(messageDef, basePackageName, version.getVersion(), null);
111 writeFile(messageClass, "message", messageElement.getName(), version);
112 }
113 }
114
115 private GroupDef parseGroupOrMessage(String messageName, XSParticle groupParticle,
116 boolean isMessage, Version version,
117 String basePackageName,
118 Map<String, StructureDef> structures) throws Exception {
119 XSElementDecl groupDecl = groupParticle.getTerm().asElementDecl();
120 XSComplexType complexType = groupDecl.getType().asComplexType();
121
122 XSParticle[] children = complexType
123 .getContentType()
124 .asParticle()
125 .getTerm()
126 .asModelGroup()
127 .getChildren();
128 LOG.debug("found {}, having {} children", groupDecl.getName(), children.length);
129
130 GroupDefpDef.html#GroupDef">GroupDef def = new GroupDef(
131 messageName,
132
133 messageName.equals(groupDecl.getName()) ?
134 messageName :
135 groupDecl.getName().substring(messageName.length() + 1),
136 groupParticle.getMinOccurs().intValue() > 0,
137 groupParticle.isRepeated(),
138 "a Group object");
139 structures.put(groupDecl.getName(), def);
140
141
142 for (XSParticle child : children) {
143 XSElementDecl childDecl = child.getTerm().asElementDecl();
144
145
146 if (childDecl.getName().startsWith(messageName)) {
147
148
149 if (structures.containsKey(childDecl.getName())) {
150 LOG.debug("{} has already been seen here", childDecl.getName());
151 def.addStructure(structures.get(childDecl.getName()));
152 } else {
153 def.addStructure(parseGroupOrMessage(messageName, child, false, version, basePackageName, structures));
154 }
155 } else {
156
157 def.addStructure(new SegmentDef(childDecl.getName(),
158 null,
159 child.getMinOccurs().intValue() > 0,
160 child.isRepeated(),
161 false,
162
163 childDecl.getName()));
164 }
165 }
166
167 if (!isMessage) {
168 String groupClass = makeGroup(def, basePackageName, version.getVersion());
169 writeFile(groupClass, "groups", def.getName(), version);
170 }
171 return def;
172 }
173
174 private void writeFile(String source, String type, String name, Version version) throws IOException {
175
176 String dirName = String.format("%s/ca/uhn/hl7v2/model/%s/%s/", targetDirectory, version.getPackageVersion(), type);
177 File dir = new File(dirName);
178 if (!dir.exists()) {
179 dir.mkdirs();
180 }
181 String targetFile = String.format("%s/%s.java", dirName, name);
182
183 try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(targetFile, false), StandardCharsets.UTF_8))) {
184 writer.write(source);
185 writer.flush();
186 }
187 }
188
189 private String makeMessage(GroupDef def, String normalBasePackageName,
190 String version, List<String> structureNameToChildNames) {
191 StringWriter out = new StringWriter();
192 Context ctx = new VelocityContext();
193 ctx.put("message", def.getRawGroupName());
194 ctx.put("specVersion", version);
195 ctx.put("chapter", "");
196 ctx.put("haveGroups", hasGroups(def));
197 ctx.put("basePackageName", normalBasePackageName);
198 ctx.put("segments", Arrays.asList(def.getStructures()));
199 ctx.put("structureNameToChildNames", structureNameToChildNames);
200 ctx.put("HASH", "#");
201
202 messageTemplate.merge(ctx, out);
203 return out.toString();
204 }
205
206 private String makeGroup(GroupDef def, String normalBasePackageName, String version) {
207 StringWriter out = new StringWriter();
208 Context ctx = new VelocityContext();
209 ctx.put("groupName", def.getName());
210 ctx.put("specVersion", version);
211 ctx.put("typeDescription", "a Group object");
212 ctx.put("basePackageName", normalBasePackageName);
213 ctx.put("groups", Arrays.asList(def.getStructures()));
214 ctx.put("chapter", "");
215
216 groupTemplate.merge(ctx, out);
217 return out.toString();
218 }
219
220
221 private static boolean hasGroups(GroupDef def) {
222 for (StructureDef structure : def.getStructures()) {
223 if (structure.isGroup()) return true;
224 }
225 return false;
226 }
227
228 public static void main(String... args) {
229 try {
230 XsdMessageGeneratortor.html#XsdMessageGenerator">XsdMessageGenerator xdtg = new XsdMessageGenerator("C:/temp", "/ca.uhn.hl7v2.sourcegen.templates");
231 long start = System.currentTimeMillis();
232
233
234
235
236 xdtg.parse(Version.V25);
237 System.out.println("Done in " + (System.currentTimeMillis() - start) + " ms.");
238 } catch (Exception e) {
239 e.printStackTrace();
240 }
241 }
242
243
244 }