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 com.rapiddweller.benerator.parser;
28
29 import com.rapiddweller.benerator.Generator;
30 import com.rapiddweller.benerator.engine.BeneratorContext;
31 import com.rapiddweller.common.ArrayFormat;
32 import com.rapiddweller.common.CollectionUtil;
33 import com.rapiddweller.common.ConfigurationError;
34 import com.rapiddweller.common.StringUtil;
35 import com.rapiddweller.common.SyntaxError;
36 import com.rapiddweller.common.converter.ToStringConverter;
37 import com.rapiddweller.common.xml.XMLUtil;
38 import com.rapiddweller.model.data.ArrayElementDescriptor;
39 import com.rapiddweller.model.data.ArrayTypeDescriptor;
40 import com.rapiddweller.model.data.ComplexTypeDescriptor;
41 import com.rapiddweller.model.data.ComponentDescriptor;
42 import com.rapiddweller.model.data.DescriptorProvider;
43 import com.rapiddweller.model.data.Entity;
44 import com.rapiddweller.model.data.EntitySource;
45 import com.rapiddweller.model.data.IdDescriptor;
46 import com.rapiddweller.model.data.InstanceDescriptor;
47 import com.rapiddweller.model.data.PartDescriptor;
48 import com.rapiddweller.model.data.ReferenceDescriptor;
49 import com.rapiddweller.model.data.SimpleTypeDescriptor;
50 import com.rapiddweller.model.data.TypeDescriptor;
51 import com.rapiddweller.model.data.VariableDescriptor;
52 import com.rapiddweller.model.data.VariableHolder;
53 import com.rapiddweller.script.expression.ConstantExpression;
54 import org.w3c.dom.Attr;
55 import org.w3c.dom.Element;
56 import org.w3c.dom.NamedNodeMap;
57
58 import java.util.Map;
59 import java.util.Set;
60
61 import static com.rapiddweller.benerator.engine.DescriptorConstants.EL_ATTRIBUTE;
62 import static com.rapiddweller.benerator.engine.DescriptorConstants.EL_ID;
63 import static com.rapiddweller.benerator.engine.DescriptorConstants.EL_PART;
64 import static com.rapiddweller.benerator.engine.DescriptorConstants.EL_REFERENCE;
65 import static com.rapiddweller.benerator.parser.xml.XmlDescriptorParser.parseStringAttribute;
66 import static com.rapiddweller.benerator.parser.xml.XmlDescriptorParser.resolveScript;
67
68
69
70
71
72
73
74
75 public class ModelParser {
76
77 private static final Set<String> SIMPLE_TYPE_COMPONENTS = CollectionUtil.toSet(EL_ATTRIBUTE, EL_REFERENCE, EL_ID);
78
79 private final BeneratorContext context;
80 private final DescriptorProvider descriptorProvider;
81
82
83
84
85
86
87 public ModelParser(BeneratorContext context) {
88 this.context = context;
89 this.descriptorProvider = context.getLocalDescriptorProvider();
90 }
91
92
93
94
95
96
97
98
99 public ComponentDescriptor parseComponent(Element element, ComplexTypeDescriptor owner) {
100 String elementName = XMLUtil.localName(element);
101 if (EL_PART.equals(elementName)) {
102 return parsePart(element, owner, null);
103 } else if (SIMPLE_TYPE_COMPONENTS.contains(elementName)) {
104 return parseSimpleTypeComponent(element, owner, null);
105 } else {
106 throw new ConfigurationError("Expected one of these element names: " +
107 EL_ATTRIBUTE + ", " + EL_ID + ", " + EL_REFERENCE + ", or " + EL_PART + ". Found: " + elementName);
108 }
109 }
110
111
112
113
114
115
116
117
118
119 public ComponentDescriptor parseSimpleTypeComponent(
120 Element element, ComplexTypeDescriptor owner, ComponentDescriptor component) {
121 String name = XMLUtil.localName(element);
122 if (EL_ATTRIBUTE.equals(name)) {
123 return parseAttribute(element, owner, component);
124 } else if (EL_ID.equals(name)) {
125 return parseId(element, owner, component);
126 } else if (EL_REFERENCE.equals(name)) {
127 return parseReference(element, owner, component);
128 } else {
129 throw new ConfigurationError("Expected one of these element names: " +
130 EL_ATTRIBUTE + ", " + EL_ID + " or " + EL_REFERENCE + ". Found: " + name);
131 }
132 }
133
134
135
136
137
138
139
140
141 public ComplexTypeDescriptoromplexTypeDescriptor.html#ComplexTypeDescriptor">ComplexTypeDescriptor parseComplexType(Element ctElement, ComplexTypeDescriptor descriptor) {
142 assertElementName(ctElement, "entity", "type");
143 descriptor = new ComplexTypeDescriptor(descriptor.getName(), descriptorProvider, descriptor);
144 mapTypeDetails(ctElement, descriptor);
145 for (Element child : XMLUtil.getChildElements(ctElement)) {
146 parseComplexTypeChild(child, descriptor);
147 }
148 return descriptor;
149 }
150
151
152
153
154
155
156
157 public void parseComplexTypeChild(Element element, ComplexTypeDescriptor descriptor) {
158 String childName = XMLUtil.localName(element);
159 if ("variable".equals(childName)) {
160 parseVariable(element, descriptor);
161 } else {
162 throw new UnsupportedOperationException("element type not supported here: " + childName);
163 }
164 }
165
166
167
168
169
170
171
172
173
174 public PartDescriptor parseAttribute(Element element, ComplexTypeDescriptor owner, ComponentDescriptor descriptor) {
175 assertElementName(element, "attribute");
176 PartDescriptor result;
177 if (descriptor != null) {
178 result = new PartDescriptor(descriptor.getName(), descriptorProvider, descriptor.getType());
179 } else {
180 String typeName = StringUtil.emptyToNull(element.getAttribute("type"));
181 result = new PartDescriptor(element.getAttribute("name"), descriptorProvider, typeName);
182 }
183 mapInstanceDetails(element, false, result);
184 applyDefaultCounts(result);
185 if (owner != null) {
186 ComponentDescriptor parentComponent = owner.getComponent(result.getName());
187 if (parentComponent != null) {
188 TypeDescriptor parentType = parentComponent.getTypeDescriptor();
189 result.getLocalType(false).setParent(parentType);
190 }
191 owner.addComponent(result);
192 }
193 return result;
194 }
195
196
197
198
199
200
201
202
203
204 public PartDescriptor parsePart(Element element, ComplexTypeDescriptor owner, ComponentDescriptor descriptor) {
205 assertElementName(element, "part");
206 PartDescriptor result;
207 if (descriptor instanceof PartDescriptor) {
208 result = (PartDescriptor) descriptor;
209 } else if (descriptor != null) {
210 result = new PartDescriptor(descriptor.getName(), descriptorProvider, descriptor.getType());
211 } else {
212 String typeName = StringUtil.emptyToNull(element.getAttribute("type"));
213 String partName = element.getAttribute("name");
214 String localTypeName = owner.getName() + "." + partName;
215 if (typeName != null) {
216 result = new PartDescriptor(partName, descriptorProvider, typeName);
217 } else if (element.getNodeName().equals("part")) {
218 result = new PartDescriptor(partName, descriptorProvider,
219 new ComplexTypeDescriptoromplexTypeDescriptor.html#ComplexTypeDescriptor">ComplexTypeDescriptor(localTypeName, descriptorProvider, (ComplexTypeDescriptor) null));
220 } else {
221 result = new PartDescriptor(partName, descriptorProvider,
222 new SimpleTypeDescriptorSimpleTypeDescriptor.html#SimpleTypeDescriptor">SimpleTypeDescriptor(localTypeName, descriptorProvider, (SimpleTypeDescriptor) null));
223 }
224 }
225 mapInstanceDetails(element, true, result);
226 if (result.getLocalType().getSource() == null) {
227 applyDefaultCounts(result);
228 }
229 if (owner != null) {
230 ComponentDescriptor parentComponent = owner.getComponent(result.getName());
231 if (parentComponent != null) {
232 TypeDescriptor parentType = parentComponent.getTypeDescriptor();
233 result.getLocalType(false).setParent(parentType);
234 }
235 owner.addComponent(result);
236 }
237 for (Element childElement : XMLUtil.getChildElements(element)) {
238 parseComponent(childElement, (ComplexTypeDescriptor) result.getLocalType(true));
239 }
240 return result;
241 }
242
243
244
245
246
247
248 public void applyDefaultCounts(PartDescriptor descriptor) {
249 if (descriptor.getDeclaredDetailValue("minCount") == null) {
250 descriptor.setMinCount(new ConstantExpression<>(1L));
251 }
252 if (descriptor.getDeclaredDetailValue("maxCount") == null) {
253 descriptor.setMaxCount(new ConstantExpression<>(1L));
254 }
255 }
256
257
258
259
260
261
262
263
264
265
266
267
268
269 public SimpleTypeDescriptorta/SimpleTypeDescriptor.html#SimpleTypeDescriptor">SimpleTypeDescriptor parseSimpleType(Element element, SimpleTypeDescriptor descriptor) {
270 assertElementName(element, "type");
271 return mapTypeDetails(element, descriptor);
272 }
273
274
275
276
277
278
279
280
281 public InstanceDescriptor parseVariable(Element varElement, VariableHolder owner) {
282 assertElementName(varElement, "variable");
283 String type = StringUtil.emptyToNull(varElement.getAttribute("type"));
284 VariableDescriptoror.html#VariableDescriptor">VariableDescriptor descriptor = new VariableDescriptor(varElement.getAttribute("name"), descriptorProvider, type);
285 VariableDescriptor variable = mapInstanceDetails(varElement, false, descriptor);
286 owner.addVariable(variable);
287 return variable;
288 }
289
290
291
292
293
294
295
296
297
298 public ArrayElementDescriptor parseSimpleTypeArrayElement(Element element, ArrayTypeDescriptor owner, int index) {
299 ArrayElementDescriptoror.html#ArrayElementDescriptor">ArrayElementDescriptor descriptor = new ArrayElementDescriptor(index, descriptorProvider, element.getAttribute("name"));
300 mapInstanceDetails(element, false, descriptor);
301 owner.addElement(descriptor);
302 return descriptor;
303 }
304
305
306
307 private <T extends TypeDescriptor> T mapTypeDetails(Element element, T descriptor) {
308 NamedNodeMap attributes = element.getAttributes();
309 for (int i = 0; i < attributes.getLength(); i++) {
310 Attr attr = (Attr) attributes.item(i);
311 String detailValue = parseStringAttribute(attr, context);
312 descriptor.setDetailValue(attr.getName(), detailValue);
313 }
314 return descriptor;
315 }
316
317 private <T extends InstanceDescriptor> T mapInstanceDetails(
318 Element element, boolean complexType, T descriptor) {
319 TypeDescriptor localType = descriptor.getLocalType();
320 Map<String, String> attributes = XMLUtil.getAttributes(element);
321 for (Map.Entry<String, String> entry : attributes.entrySet()) {
322 String detailName = entry.getKey();
323 if (detailName.equals("type")) {
324 continue;
325 }
326 Object tmp = resolveScript(detailName, entry.getValue(), context);
327 String detailString = ToStringConverter.convert(tmp, null);
328 if (descriptor.supportsDetail(detailName)) {
329 try {
330 descriptor.setDetailValue(detailName, detailString);
331 } catch (IllegalArgumentException e) {
332 throw new SyntaxError("Error parsing '" + detailName + "'", e, String.valueOf(detailString), -1, -1);
333 }
334 } else {
335 if (localType == null) {
336 String partType = attributes.get("type");
337 if (partType == null) {
338 partType = descriptor.getType();
339 }
340 if (partType == null) {
341 String sourceSpec = attributes.get("source");
342 if (sourceSpec != null) {
343 Object source = context.get(sourceSpec);
344 if (source != null) {
345 if (source instanceof Generator) {
346 if (((Generator<?>) source).getGeneratedType() == Entity.class) {
347 partType = "entity";
348 }
349 } else if (source instanceof EntitySource) {
350 partType = "entity";
351 }
352 } else {
353 String lcSourceSpec = sourceSpec.toLowerCase();
354 if (lcSourceSpec.endsWith(".ent.csv")
355 || lcSourceSpec.endsWith(".ent.fcw")
356 || lcSourceSpec.endsWith(".dbunit.xml")) {
357 partType = "entity";
358 }
359 }
360 }
361 }
362 if (partType != null) {
363 TypeDescriptor localTypeParent = context.getDataModel().getTypeDescriptor(partType);
364 localType = (localTypeParent instanceof ComplexTypeDescriptor ?
365 new ComplexTypeDescriptor(partType, descriptorProvider, partType) :
366 new SimpleTypeDescriptor(partType, descriptorProvider, partType));
367 }
368 descriptor.setLocalType(localType);
369 }
370 if (localType == null) {
371 localType = descriptor.getLocalType(complexType);
372 }
373 localType.setDetailValue(detailName, detailString);
374 }
375 }
376 return descriptor;
377 }
378
379 private static void assertElementName(Element element, String... expectedNames) {
380 String elementName = XMLUtil.localName(element);
381 for (String expectedName : expectedNames) {
382 if (elementName.equals(expectedName)) {
383 return;
384 }
385 }
386 String message;
387 if (expectedNames.length == 1) {
388 message = "Expected element '" + expectedNames[0] + "', found: " + elementName;
389 } else {
390 message = "Expected one of these element names: '" + ArrayFormat.format(expectedNames) + "', " +
391 "found: " + elementName;
392 }
393 throw new IllegalArgumentException(message);
394 }
395
396 private IdDescriptor parseId(Element element, ComplexTypeDescriptor owner, ComponentDescriptor descriptor) {
397 assertElementName(element, "id");
398 IdDescriptor result;
399 IdDescriptor resultTmp;
400 if (descriptor instanceof IdDescriptor) {
401 resultTmp = (IdDescriptor) descriptor;
402 } else if (descriptor != null) {
403 resultTmp = new IdDescriptor(descriptor.getName(), descriptorProvider, descriptor.getType());
404 } else {
405 resultTmp = new IdDescriptor(element.getAttribute("name"), descriptorProvider, element.getAttribute("type"));
406 }
407 result = mapInstanceDetails(element, false, resultTmp);
408 if (owner != null) {
409 ComponentDescriptor parentComponent = owner.getComponent(result.getName());
410 if (parentComponent != null) {
411 TypeDescriptor parentType = parentComponent.getTypeDescriptor();
412 result.getLocalType(false).setParent(parentType);
413 }
414 owner.addComponent(result);
415 }
416 return result;
417 }
418
419 private ReferenceDescriptor parseReference(Element element, ComplexTypeDescriptor owner, ComponentDescriptor component) {
420 assertElementName(element, "reference");
421 ReferenceDescriptor result;
422 if (component instanceof ReferenceDescriptor) {
423 result = (ReferenceDescriptor) component;
424 } else if (component != null) {
425 result = new ReferenceDescriptor(component.getName(), descriptorProvider, component.getType());
426 } else {
427 result = new ReferenceDescriptor(element.getAttribute("name"), descriptorProvider, StringUtil.emptyToNull(element.getAttribute("type")));
428 }
429 if (owner != null) {
430 ComponentDescriptor parentComponent = owner.getComponent(result.getName());
431 if (parentComponent != null) {
432 TypeDescriptor parentType = parentComponent.getTypeDescriptor();
433 result.getLocalType(false).setParent(parentType);
434 }
435 owner.addComponent(result);
436 }
437 return mapInstanceDetails(element, false, result);
438 }
439
440
441 }