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.engine.parser.xml;
28
29 import com.rapiddweller.benerator.BeneratorFactory;
30 import com.rapiddweller.benerator.Consumer;
31 import com.rapiddweller.benerator.Generator;
32 import com.rapiddweller.benerator.composite.GeneratorComponent;
33 import com.rapiddweller.benerator.engine.BeneratorContext;
34 import com.rapiddweller.benerator.engine.CurrentProductGeneration;
35 import com.rapiddweller.benerator.engine.ResourceManager;
36 import com.rapiddweller.benerator.engine.Statement;
37 import com.rapiddweller.benerator.engine.expression.CachedExpression;
38 import com.rapiddweller.benerator.engine.expression.xml.XMLConsumerExpression;
39 import com.rapiddweller.benerator.engine.statement.ConversionStatement;
40 import com.rapiddweller.benerator.engine.statement.GenerateAndConsumeTask;
41 import com.rapiddweller.benerator.engine.statement.GenerateOrIterateStatement;
42 import com.rapiddweller.benerator.engine.statement.LazyStatement;
43 import com.rapiddweller.benerator.engine.statement.TimedGeneratorStatement;
44 import com.rapiddweller.benerator.engine.statement.ValidationStatement;
45 import com.rapiddweller.benerator.factory.DescriptorUtil;
46 import com.rapiddweller.benerator.factory.GeneratorComponentFactory;
47 import com.rapiddweller.benerator.factory.MetaGeneratorFactory;
48 import com.rapiddweller.benerator.parser.ModelParser;
49 import com.rapiddweller.common.CollectionUtil;
50 import com.rapiddweller.common.Context;
51 import com.rapiddweller.common.Converter;
52 import com.rapiddweller.common.ErrorHandler;
53 import com.rapiddweller.common.StringUtil;
54 import com.rapiddweller.common.Validator;
55 import com.rapiddweller.common.xml.XMLUtil;
56 import com.rapiddweller.model.data.ArrayTypeDescriptor;
57 import com.rapiddweller.model.data.ComplexTypeDescriptor;
58 import com.rapiddweller.model.data.ComponentDescriptor;
59 import com.rapiddweller.model.data.DescriptorProvider;
60 import com.rapiddweller.model.data.InstanceDescriptor;
61 import com.rapiddweller.model.data.TypeDescriptor;
62 import com.rapiddweller.model.data.Uniqueness;
63 import com.rapiddweller.model.data.VariableHolder;
64 import com.rapiddweller.script.DatabeneScriptParser;
65 import com.rapiddweller.script.Expression;
66 import com.rapiddweller.script.PrimitiveType;
67 import com.rapiddweller.script.expression.DynamicExpression;
68 import com.rapiddweller.task.PageListener;
69 import org.apache.logging.log4j.LogManager;
70 import org.apache.logging.log4j.Logger;
71 import org.w3c.dom.Element;
72
73 import java.util.ArrayList;
74 import java.util.HashSet;
75 import java.util.List;
76 import java.util.Map;
77 import java.util.Set;
78
79 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_CONSUMER;
80 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_CONTAINER;
81 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_CONVERTER;
82 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_COUNT;
83 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_COUNT_DISTRIBUTION;
84 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_CYCLIC;
85 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_DATASET;
86 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_DISTRIBUTION;
87 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_ENCODING;
88 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_FILTER;
89 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_FORMAT;
90 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_GENERATOR;
91 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_LOCALE;
92 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_MAX_COUNT;
93 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_MIN_COUNT;
94 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_NAME;
95 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_NESTING;
96 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_NULL_QUOTA;
97 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_OFFSET;
98 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_ON_ERROR;
99 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_PAGER;
100 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_PAGESIZE;
101 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_SEGMENT;
102 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_SELECTOR;
103 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_SEPARATOR;
104 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_SOURCE;
105 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_STATS;
106 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_SUB_SELECTOR;
107 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_TEMPLATE;
108 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_TYPE;
109 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_UNIQUE;
110 import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_VALIDATOR;
111 import static com.rapiddweller.benerator.engine.DescriptorConstants.COMPONENT_TYPES;
112 import static com.rapiddweller.benerator.engine.DescriptorConstants.CREATE_ENTITIES_EXT_SETUP;
113 import static com.rapiddweller.benerator.engine.DescriptorConstants.EL_CONSUMER;
114 import static com.rapiddweller.benerator.engine.DescriptorConstants.EL_GENERATE;
115 import static com.rapiddweller.benerator.engine.DescriptorConstants.EL_ITERATE;
116 import static com.rapiddweller.benerator.engine.DescriptorConstants.EL_VALUE;
117 import static com.rapiddweller.benerator.engine.DescriptorConstants.EL_VARIABLE;
118 import static com.rapiddweller.benerator.parser.xml.XmlDescriptorParser.parseStringAttribute;
119
120
121
122
123
124
125
126
127 public class GenerateOrIterateParser extends AbstractBeneratorDescriptorParser {
128
129 private static final Logger logger = LogManager.getLogger(GenerateOrIterateParser.class);
130
131 private static final Set<String> OPTIONAL_ATTRIBUTES = CollectionUtil.toSet(
132 ATT_COUNT, ATT_MIN_COUNT, ATT_MAX_COUNT, ATT_COUNT_DISTRIBUTION,
133 ATT_PAGESIZE, ATT_STATS, ATT_ON_ERROR,
134 ATT_TEMPLATE, ATT_CONSUMER,
135 ATT_NAME, ATT_TYPE, ATT_CONTAINER, ATT_GENERATOR, ATT_VALIDATOR,
136 ATT_CONVERTER, ATT_NULL_QUOTA, ATT_UNIQUE, ATT_DISTRIBUTION, ATT_CYCLIC,
137 ATT_SOURCE, ATT_SEGMENT, ATT_FORMAT, ATT_OFFSET, ATT_SEPARATOR, ATT_ENCODING, ATT_SELECTOR, ATT_SUB_SELECTOR,
138 ATT_DATASET, ATT_NESTING, ATT_LOCALE, ATT_FILTER
139 );
140
141
142 private static final Set<String> CONSUMER_EXPECTING_ELEMENTS = CollectionUtil.toSet(EL_GENERATE, EL_ITERATE);
143
144
145
146
147
148
149 public GenerateOrIterateParser() {
150 super("", null, OPTIONAL_ATTRIBUTES);
151 }
152
153 private static List<String> createProfilerPath(Statement./../../../com/rapiddweller/benerator/engine/Statement.html#Statement">Statement[] parentPath, Statement currentElement) {
154 List<String> path = new ArrayList<>(parentPath != null ? parentPath.length + 1 : 1);
155 if (parentPath != null) {
156 for (Statement statement : parentPath) {
157 path.add(statement.toString());
158 }
159 }
160 path.add(currentElement.toString());
161 return path;
162 }
163
164 private static String getNameOrType(Element element) {
165 String result = element.getAttribute(ATT_NAME);
166 if (StringUtil.isEmpty(result)) {
167 result = element.getAttribute(ATT_TYPE);
168 }
169 if (StringUtil.isEmpty(result)) {
170 result = "anonymous";
171 }
172 return result;
173 }
174
175
176
177 private static Expression<Consumer> parseConsumers(Element entityElement, boolean consumersExpected, ResourceManager resourceManager) {
178 return new CachedExpression<>(new XMLConsumerExpression(entityElement, consumersExpected, resourceManager));
179 }
180
181 private static InstanceDescriptor mapDescriptorElement(Element element, BeneratorContext context) {
182
183
184
185 String type = parseStringAttribute(element, ATT_TYPE, context, false);
186 TypeDescriptor localType;
187 DescriptorProvider localDescriptorProvider = context.getLocalDescriptorProvider();
188 if (PrimitiveType.ARRAY.getName().equals(type)
189 || XMLUtil.getChildElements(element, false, EL_VALUE).length > 0) {
190 localType = new ArrayTypeDescriptor(element.getAttribute(ATT_NAME), localDescriptorProvider);
191 } else {
192 TypeDescriptor parentType = context.getDataModel().getTypeDescriptor(type);
193 if (parentType != null) {
194 type = parentType.getName();
195 localType = new ComplexTypeDescriptorTypeDescriptor.html#ComplexTypeDescriptor">ComplexTypeDescriptor(parentType.getName(), localDescriptorProvider, (ComplexTypeDescriptor) parentType);
196 } else {
197 localType = new ComplexTypeDescriptor(type, localDescriptorProvider, "entity");
198 }
199 }
200
201
202 InstanceDescriptorDescriptor.html#InstanceDescriptor">InstanceDescriptor instance = new InstanceDescriptor(type, localDescriptorProvider, type);
203 instance.setLocalType(localType);
204
205
206 for (Map.Entry<String, String> attribute : XMLUtil.getAttributes(element).entrySet()) {
207 String attributeName = attribute.getKey();
208 if (!CREATE_ENTITIES_EXT_SETUP.contains(attributeName)) {
209 Object attributeValue = attribute.getValue();
210 if (instance.supportsDetail(attributeName)) {
211 instance.setDetailValue(attributeName, attributeValue);
212 } else {
213 localType.setDetailValue(attributeName, attributeValue);
214 }
215 }
216 }
217
218 DescriptorUtil.parseComponentConfig(element, instance.getLocalType(), context);
219 return instance;
220 }
221
222 @Override
223 public boolean supports(Element element, Statement[] parentPath) {
224 String name = element.getNodeName();
225 return EL_GENERATE.equals(name) || EL_ITERATE.equals(name);
226 }
227
228 @Override
229 public Statement doPStatementong class="jxr_keyword">final Element element, final Statement[] parentPath,
230 final BeneratorParseContext pContext) {
231 final boolean looped = AbstractBeneratorDescriptorParser.containsLoop(parentPath);
232 final boolean nested = AbstractBeneratorDescriptorParser.containsGeneratorStatement(parentPath);
233 Expression<Statement> expression = new DynamicExpression<>() {
234 @Override
235 public Statement evaluate(Context context) {
236 return parseGenerate(
237 element, parentPath, pContext, (BeneratorContext) context, !looped, nested);
238 }
239
240 @Override
241 public String toString() {
242 return XMLUtil.formatShort(element);
243 }
244 };
245 Statement statement = new LazyStatement(expression);
246 statement = new TimedGeneratorStatement(getNameOrType(element), statement, createProfilerPath(parentPath, statement), !looped);
247 return statement;
248 }
249
250
251
252
253
254
255
256
257
258
259
260
261 @SuppressWarnings("unchecked")
262 public GenerateOrIterateStatement parseGenerate(Element element, Statement[] parentPath,
263 BeneratorParseContext parsingContext, BeneratorContext context, boolean infoLog, boolean nested) {
264
265 InstanceDescriptor descriptor = mapDescriptorElement(element, context);
266
267
268 Generator<Long> countGenerator = DescriptorUtil.createDynamicCountGenerator(descriptor, 0L, 1L, false, context);
269 Expression<Long> pageSize = parsePageSize(element);
270 Expression<PageListener> pager = (Expression<PageListener>) DatabeneScriptParser.parseBeanSpec(
271 element.getAttribute(ATT_PAGER));
272 Expression<ErrorHandler> errorHandler = parseOnErrorAttribute(element, element.getAttribute(ATT_NAME));
273 Expression<Long> minCount = DescriptorUtil.getMinCount(descriptor, 0L);
274 GenerateOrIterateStatement statement = createStatement(getTaskName(descriptor), countGenerator, minCount, pageSize, pager, infoLog,
275 nested, element, errorHandler, context);
276
277
278 GenerateAndConsumeTask task = parseTask(element, parentPath, statement, parsingContext, descriptor, infoLog);
279 statement.setTask(task);
280 return statement;
281 }
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298 protected GenerateOrIterateStatement createStatement(String productName, Generator<Long> countGenerator,
299 Expression<Long> minCount, Expression<Long> pageSize,
300 Expression<PageListener> pager, boolean infoLog,
301 boolean nested, Element element,
302 Expression<ErrorHandler> errorHandler, BeneratorContext context) {
303 return new GenerateOrIterateStatement(productName, countGenerator, minCount, pageSize, pager,
304 errorHandler, infoLog, nested, context);
305 }
306
307 @SuppressWarnings({"unchecked", "rawtypes"})
308 private GenerateAndConsumeTask parseTask(Element element, Statement[] parentPath, GenerateOrIterateStatement statement,
309 BeneratorParseContext parseContext, InstanceDescriptor descriptor, boolean infoLog) {
310 descriptor.setNullable(false);
311 if (infoLog) {
312 logger.debug("{}", descriptor);
313 }
314
315 String taskName = getTaskName(descriptor);
316 BeneratorContext context = statement.getContext();
317 BeneratorContext childContext = statement.getChildContext();
318 String productName = getNameOrType(element);
319
320
321 List<Statement> statements = new ArrayList<>();
322
323
324 Generator<?> base = MetaGeneratorFactory.createRootGenerator(descriptor, Uniqueness.NONE, context);
325 statements.add(new CurrentProductGeneration(productName, base));
326
327
328 ModelParserparser/ModelParser.html#ModelParser">ModelParser parser = new ModelParser(childContext);
329 TypeDescriptor type = descriptor.getTypeDescriptor();
330 int arrayIndex = 0;
331 Element[] childElements = XMLUtil.getChildElements(element);
332 Set<String> handledMembers = new HashSet<>();
333 for (Element child : childElements) {
334 String childName = XMLUtil.localName(child);
335
336 InstanceDescriptor componentDescriptor = null;
337 if (EL_VARIABLE.equals(childName)) {
338 componentDescriptor = parser.parseVariable(child, (VariableHolder) type);
339 } else if (COMPONENT_TYPES.contains(childName)) {
340 componentDescriptor = parser.parseComponent(child, (ComplexTypeDescriptor) type);
341 handledMembers.add(componentDescriptor.getName().toLowerCase());
342 } else if (EL_VALUE.equals(childName)) {
343 componentDescriptor = parser.parseSimpleTypeArrayElement(child, (ArrayTypeDescriptor) type, arrayIndex++);
344 }
345
346 if (componentDescriptor != null) {
347 GeneratorComponent<?> componentGenerator = GeneratorComponentFactory.createGeneratorComponent(
348 componentDescriptor, Uniqueness.NONE, childContext);
349 if (componentGenerator != null) {
350 statements.add(componentGenerator);
351 }
352 } else if (!EL_CONSUMER.equals(childName)) {
353 Statement[] subPath = parseContext.createSubPath(parentPath, statement);
354 Statement subStatement = parseContext.parseChildElement(child, subPath);
355 statements.add(subStatement);
356 }
357 }
358
359 if (EL_GENERATE.equals(element.getNodeName())) {
360 if (!StringUtil.isEmpty(element.getAttribute(ATT_SOURCE))) {
361 syntaxError("'source' not allowed in <generate>", element);
362 }
363 TypeDescriptor pType = type.getParent();
364 if (pType instanceof ComplexTypeDescriptor) {
365
366 int insertionIndex = statements.size() - 1;
367 for (; insertionIndex >= 0; insertionIndex--) {
368 Statement tmp = statements.get(insertionIndex);
369 if (tmp instanceof GeneratorComponent || tmp instanceof CurrentProductGeneration) {
370 break;
371 }
372 }
373 insertionIndex++;
374
375 ComplexTypeDescriptorom/rapiddweller/model/data/ComplexTypeDescriptor.html#ComplexTypeDescriptor">ComplexTypeDescriptor parentType = (ComplexTypeDescriptor) pType;
376 for (ComponentDescriptor component : parentType.getComponents()) {
377 String componentName = component.getName();
378 if (handledMembers.contains(componentName.toLowerCase())) {
379 continue;
380 }
381 GeneratorComponent<?> componentGenerator = GeneratorComponentFactory.createGeneratorComponent(
382 component, Uniqueness.NONE, childContext);
383 statements.add(insertionIndex++, componentGenerator);
384 }
385 }
386 } else {
387 if (StringUtil.isEmpty(element.getAttribute(ATT_SOURCE))) {
388 syntaxError("'source' mising in <iterate>", element);
389 }
390 }
391
392
393 GenerateAndConsumeTask task = createTask(taskName, productName);
394 task.setStatements(statements);
395
396
397 Converter converter = DescriptorUtil.getConverter(element.getAttribute(ATT_CONVERTER), context);
398 if (converter != null) {
399 task.addStatement(new ConversionStatement(BeneratorFactory.getInstance().configureConverter(converter, context)));
400 }
401
402
403 Validator validator = DescriptorUtil.getValidator(element.getAttribute(ATT_VALIDATOR), context);
404 if (validator != null) {
405 task.addStatement(new ValidationStatement(BeneratorFactory.getInstance().configureValidator(validator, context)));
406 }
407
408
409 boolean consumerExpected = CONSUMER_EXPECTING_ELEMENTS.contains(element.getNodeName());
410 Expression consumer = parseConsumers(element, consumerExpected, task.getResourceManager());
411 task.setConsumer(consumer);
412
413 return task;
414 }
415
416
417
418
419
420
421
422 protected String getTaskName(InstanceDescriptor descriptor) {
423 String taskName = descriptor.getName();
424 if (taskName == null) {
425 taskName = descriptor.getLocalType().getSource();
426 }
427 return taskName;
428 }
429
430
431
432
433
434
435
436
437 protected GenerateAndConsumeTask createTask(String taskName, String productName) {
438 return new GenerateAndConsumeTask(taskName, productName);
439 }
440
441 }