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.factory;
28
29 import com.rapiddweller.benerator.Generator;
30 import com.rapiddweller.benerator.StorageSystem;
31 import com.rapiddweller.benerator.csv.SequencedDatasetCSVGenerator;
32 import com.rapiddweller.benerator.csv.WeightedDatasetCSVGenerator;
33 import com.rapiddweller.benerator.distribution.Distribution;
34 import com.rapiddweller.benerator.distribution.IndividualWeight;
35 import com.rapiddweller.benerator.distribution.sequence.RandomIntegerGenerator;
36 import com.rapiddweller.benerator.engine.BeneratorContext;
37 import com.rapiddweller.benerator.engine.DescriptorConstants;
38 import com.rapiddweller.benerator.sample.ConstantGenerator;
39 import com.rapiddweller.benerator.sample.WeightedCSVSampleGenerator;
40 import com.rapiddweller.benerator.wrapper.AccessingGenerator;
41 import com.rapiddweller.benerator.wrapper.AlternativeGenerator;
42 import com.rapiddweller.benerator.wrapper.AsByteGeneratorWrapper;
43 import com.rapiddweller.benerator.wrapper.ByteArrayGenerator;
44 import com.rapiddweller.benerator.wrapper.DataSourceGenerator;
45 import com.rapiddweller.benerator.wrapper.WrapperFactory;
46 import com.rapiddweller.common.ConfigurationError;
47 import com.rapiddweller.common.Converter;
48 import com.rapiddweller.common.StringUtil;
49 import com.rapiddweller.common.Validator;
50 import com.rapiddweller.common.accessor.GraphAccessor;
51 import com.rapiddweller.common.converter.AnyConverter;
52 import com.rapiddweller.common.converter.ArrayElementExtractor;
53 import com.rapiddweller.common.converter.ConditionalConverter;
54 import com.rapiddweller.common.converter.ConverterChain;
55 import com.rapiddweller.common.converter.DateString2DurationConverter;
56 import com.rapiddweller.common.converter.LiteralParser;
57 import com.rapiddweller.common.converter.ToStringConverter;
58 import com.rapiddweller.common.validator.StringLengthValidator;
59 import com.rapiddweller.format.DataSource;
60 import com.rapiddweller.format.script.ScriptConverterForStrings;
61 import com.rapiddweller.format.util.DataFileUtil;
62 import com.rapiddweller.model.data.SimpleTypeDescriptor;
63 import com.rapiddweller.model.data.UnionSimpleTypeDescriptor;
64 import com.rapiddweller.model.data.Uniqueness;
65 import com.rapiddweller.script.BeanSpec;
66 import com.rapiddweller.script.DatabeneScriptParser;
67 import com.rapiddweller.script.PrimitiveType;
68
69 import java.lang.annotation.Annotation;
70 import java.sql.Timestamp;
71 import java.text.DateFormat;
72 import java.util.Date;
73 import java.util.Locale;
74
75 import static com.rapiddweller.model.data.SimpleTypeDescriptor.GRANULARITY;
76 import static com.rapiddweller.model.data.SimpleTypeDescriptor.MAX;
77 import static com.rapiddweller.model.data.SimpleTypeDescriptor.MIN;
78 import static com.rapiddweller.model.data.SimpleTypeDescriptor.PATTERN;
79
80
81
82
83
84
85
86 public class SimpleTypeGeneratorFactory extends TypeGeneratorFactory<SimpleTypeDescriptor> {
87
88 private static final SimpleTypeGeneratorFactoryatorFactory.html#SimpleTypeGeneratorFactory">SimpleTypeGeneratorFactory INSTANCE = new SimpleTypeGeneratorFactory();
89
90
91
92
93
94
95 public static SimpleTypeGeneratorFactory getInstance() {
96 return INSTANCE;
97 }
98
99
100
101
102 protected SimpleTypeGeneratorFactory() {
103 }
104
105 @Override
106 protected Generator<?> createExplicitGenerator(SimpleTypeDescriptor descriptor, Uniqueness uniqueness,
107 BeneratorContext context) {
108 Generator<?> generator = super.createExplicitGenerator(descriptor, uniqueness, context);
109 if (generator == null) {
110 generator = createConstantGenerator(descriptor, context);
111 }
112 if (generator == null) {
113 generator = createValuesGenerator(descriptor, uniqueness, context);
114 }
115 if (generator == null) {
116 generator = createPatternGenerator(descriptor, uniqueness, context);
117 }
118 return generator;
119 }
120
121 @Override
122 @SuppressWarnings({"rawtypes", "unchecked"})
123 protected Generator<?> createSpecificGenerator(SimpleTypeDescriptor descriptor, String instanceName,
124 boolean nullable, Uniqueness uniqueness, BeneratorContext context) {
125 Generator<?> generator = InstanceGeneratorFactory.createConfiguredDefaultGenerator(
126 instanceName, uniqueness, context);
127 if (generator == null && nullable && shouldNullifyEachNullable(context)) {
128 generator = new ConstantGenerator(null, getGeneratedType(descriptor));
129 }
130 return generator;
131 }
132
133
134
135
136
137
138
139
140
141 protected static Generator<?> createValuesGenerator(
142 SimpleTypeDescriptor descriptor, Uniqueness uniqueness, BeneratorContext context) {
143 PrimitiveType primitiveType = descriptor.getPrimitiveType();
144 Class<?> targetType = (primitiveType != null ? primitiveType.getJavaType() : String.class);
145 String valueSpec = descriptor.getValues();
146 if (valueSpec == null) {
147 return null;
148 }
149 if ("".equals(valueSpec)) {
150 return new ConstantGenerator<>("");
151 }
152 try {
153 Distribution distribution = FactoryUtil.getDistribution(descriptor.getDistribution(), uniqueness, false, context);
154 return context.getGeneratorFactory().createFromWeightedLiteralList(valueSpec, targetType, distribution, uniqueness.isUnique());
155 } catch (com.rapiddweller.common.ParseException e) {
156 throw new ConfigurationError("Error parsing samples: " + valueSpec, e);
157 }
158 }
159
160
161
162
163
164
165
166
167
168 protected static Generator<String> createPatternGenerator(SimpleTypeDescriptor type, Uniqueness uniqueness,
169 BeneratorContext context) {
170 String pattern = type.getPattern();
171 if (pattern != null) {
172 return createStringGenerator(type, uniqueness, context);
173 } else {
174 return null;
175 }
176 }
177
178
179
180
181
182
183
184
185 @SuppressWarnings({"unchecked", "rawtypes"})
186 protected static Generator<?> createConstantGenerator(
187 SimpleTypeDescriptor descriptor, BeneratorContext context) {
188 Generator<?> generator = null;
189
190 String constant = descriptor.getConstant();
191 if ("".equals(constant)) {
192 generator = new ConstantGenerator<>("");
193 } else if (constant != null) {
194 Object value = LiteralParser.parse(constant);
195 generator = new ConstantGenerator(value);
196 }
197 return generator;
198 }
199
200 @Override
201 protected Generator<?> createHeuristicGenerator(
202 SimpleTypeDescriptor descriptor, String instanceName, Uniqueness uniqueness, BeneratorContext context) {
203 Generator<?> generator = createTypeGenerator(descriptor, uniqueness, context);
204 if (generator == null) {
205 generator = createStringGenerator(descriptor, uniqueness, context);
206 }
207 return generator;
208 }
209
210 @Override
211 @SuppressWarnings({"unchecked", "rawtypes"})
212 protected Generator<?> createSourceGenerator(
213 SimpleTypeDescriptor descriptor, Uniqueness uniqueness, BeneratorContext context) {
214 String source = descriptor.getSource();
215 if (source == null) {
216 return null;
217 }
218 String selector = descriptor.getSelector();
219 String subSelector = descriptor.getSubSelector();
220 Generator<?> generator;
221 if (context.get(source) != null) {
222 Object sourceObject = context.get(source);
223 if (sourceObject instanceof StorageSystem) {
224 if (!StringUtil.isEmpty(subSelector)) {
225 generator = new DataSourceGenerator(((StorageSystem) sourceObject).query(subSelector, true, context));
226 generator = WrapperFactory.applyHeadCycler(generator);
227 } else {
228 generator = new DataSourceGenerator(((StorageSystem) sourceObject).query(selector, true, context));
229 }
230 } else if (sourceObject instanceof Generator) {
231 generator = (Generator<?>) sourceObject;
232 } else if (sourceObject instanceof DataSource) {
233 DataSource dataSource = (DataSource) sourceObject;
234 generator = new DataSourceGenerator(dataSource);
235 } else {
236 throw new UnsupportedOperationException("Not a supported source: " + sourceObject);
237 }
238 } else if (DataFileUtil.isCsvDocument(source)) {
239 return createSimpleTypeCSVSourceGenerator(descriptor, source, uniqueness, context);
240 } else if (DataFileUtil.isExcelDocument(source)) {
241 return createSimpleTypeXLSSourceGenerator(descriptor, source, uniqueness, context);
242 } else if (DataFileUtil.isPlainTextDocument(source)) {
243 generator = SourceFactory.createTextLineGenerator(source);
244 } else {
245 try {
246 BeanSpec sourceSpec = DatabeneScriptParser.resolveBeanSpec(source, context);
247 generator = createSourceGeneratorFromObject(descriptor, context, sourceSpec);
248 } catch (Exception e) {
249 generator = new AccessingGenerator(Object.class, new GraphAccessor(source), context);
250 }
251 }
252
253 Distribution distribution = FactoryUtil.getDistribution(descriptor.getDistribution(), uniqueness, false, context);
254 if (distribution != null) {
255 generator = distribution.applyTo(generator, uniqueness.isUnique());
256 }
257
258 return generator;
259 }
260
261 @SuppressWarnings({"unchecked", "rawtypes"})
262 private static Generator<?> createSourceGeneratorFromObject(SimpleTypeDescriptor descriptor,
263 BeneratorContext context, BeanSpec sourceSpec) {
264 Object sourceObject = sourceSpec.getBean();
265 Generator<?> generator;
266 if (sourceObject instanceof StorageSystem) {
267 StorageSystem/../com/rapiddweller/benerator/StorageSystem.html#StorageSystem">StorageSystem storage = (StorageSystem) sourceObject;
268 String selector = descriptor.getSelector();
269 String subSelector = descriptor.getSubSelector();
270 if (!StringUtil.isEmpty(subSelector)) {
271 generator = new DataSourceGenerator(storage.queryEntities(descriptor.getName(), subSelector, context));
272 generator = WrapperFactory.applyHeadCycler(generator);
273 } else {
274 generator = new DataSourceGenerator(storage.queryEntities(descriptor.getName(), selector, context));
275 }
276 } else if (sourceObject instanceof Generator) {
277 generator = (Generator<?>) sourceObject;
278 } else {
279 throw new UnsupportedOperationException("Source type not supported: " + sourceObject.getClass());
280 }
281 if (sourceSpec.isReference()) {
282 generator = WrapperFactory.preventClosing(generator);
283 }
284 return generator;
285 }
286
287 @SuppressWarnings({"unchecked", "rawtypes"})
288 private static Generator<?> createSimpleTypeCSVSourceGenerator(
289 SimpleTypeDescriptor descriptor, String sourceName, Uniqueness uniqueness, BeneratorContext context) {
290 String sourceUri = context.resolveRelativeUri(sourceName);
291 Generator<?> generator;
292 char separator = DescriptorUtil.getSeparator(descriptor, context);
293 boolean rowBased = (descriptor.isRowBased() == null || descriptor.isRowBased());
294 String encoding = descriptor.getEncoding();
295 if (encoding == null) {
296 encoding = context.getDefaultEncoding();
297 }
298 Distribution distribution = FactoryUtil.getDistribution(descriptor.getDistribution(), uniqueness, false, context);
299
300 String dataset = descriptor.getDataset();
301 String nesting = descriptor.getNesting();
302 if (dataset != null && nesting != null) {
303 if (uniqueness.isUnique()) {
304 generator = new SequencedDatasetCSVGenerator(sourceUri, separator, dataset, nesting,
305 distribution, encoding, new ScriptConverterForStrings(context));
306 } else {
307 generator = new WeightedDatasetCSVGenerator(Object.class, sourceUri, separator, dataset, nesting, false,
308 encoding, new ScriptConverterForStrings(context));
309 }
310 } else if (sourceName.toLowerCase().endsWith(".wgt.csv") || distribution instanceof IndividualWeight) {
311 generator = new WeightedCSVSampleGenerator(
312 Object.class, sourceUri, encoding, new ScriptConverterForStrings(context));
313 } else {
314 Generator<String[]> src = SourceFactory.createCSVGenerator(sourceUri, separator, encoding, true, rowBased);
315 Converter<String[], Object> converterChain = new ConverterChain<>(
316 new ArrayElementExtractor<>(String.class, 0),
317 new ScriptConverterForStrings(context));
318 generator = WrapperFactory.applyConverter(src, converterChain);
319 if (distribution != null) {
320 generator = distribution.applyTo(generator, uniqueness.isUnique());
321 }
322 }
323 return generator;
324 }
325
326 private static Generator<?> createSimpleTypeXLSSourceGenerator(
327 SimpleTypeDescriptor descriptor, String sourceName, Uniqueness uniqueness, BeneratorContext context) {
328
329 Generator<?> generator;
330 Distribution distribution = FactoryUtil.getDistribution(descriptor.getDistribution(), uniqueness, false, context);
331 Generator<Object[]> src = SourceFactory.createXLSLineGenerator(sourceName);
332 Converter<Object[], Object> converterChain = new ConverterChain<>(
333 new ArrayElementExtractor<>(Object.class, 0),
334 new ConditionalConverter(argument -> (argument instanceof String),
335 new ScriptConverterForStrings(context)));
336 generator = WrapperFactory.applyConverter(src, converterChain);
337 if (distribution != null) {
338 generator = distribution.applyTo(generator, uniqueness.isUnique());
339 }
340 return generator;
341 }
342
343
344 @SuppressWarnings("unchecked")
345 private Generator<?> createTypeGenerator(
346 SimpleTypeDescriptor descriptor, Uniqueness uniqueness, BeneratorContext context) {
347 if (descriptor instanceof UnionSimpleTypeDescriptor) {
348 return createUnionTypeGenerator((UnionSimpleTypeDescriptor) descriptor, context);
349 }
350 PrimitiveType primitiveType = descriptor.getPrimitiveType();
351 if (primitiveType == null) {
352 return null;
353 }
354 Class<?> targetType = primitiveType.getJavaType();
355 if (Number.class.isAssignableFrom(targetType)) {
356 return createNumberGenerator(descriptor, (Class<? extends Number>) targetType, uniqueness, context);
357 } else if (String.class.isAssignableFrom(targetType)) {
358 return createStringGenerator(descriptor, uniqueness, context);
359 } else if (Boolean.class == targetType) {
360 return createBooleanGenerator(descriptor, context);
361 } else if (Character.class == targetType) {
362 return createCharacterGenerator(descriptor, uniqueness, context);
363 } else if (Date.class == targetType) {
364 return createDateGenerator(descriptor, uniqueness, context);
365 } else if (Timestamp.class == targetType) {
366 return createTimestampGenerator(descriptor, uniqueness, context);
367 } else if (byte[].class == targetType) {
368 return createByteArrayGenerator(descriptor, context);
369 } else {
370 return null;
371 }
372 }
373
374 @Override
375 protected Class<?> getGeneratedType(SimpleTypeDescriptor descriptor) {
376 PrimitiveType primitiveType = descriptor.getPrimitiveType();
377 if (primitiveType == null) {
378 throw new ConfigurationError("No type configured for " + descriptor.getName());
379 }
380 return primitiveType.getJavaType();
381 }
382
383 @SuppressWarnings({"unchecked", "rawtypes"})
384 private Generator<?> createUnionTypeGenerator(
385 UnionSimpleTypeDescriptor descriptor, BeneratorContext context) {
386 int n = descriptor.getAlternatives().size();
387 Generator<?>[] sources = new Generator[n];
388 for (int i = 0; i < n; i++) {
389 SimpleTypeDescriptor alternative = descriptor.getAlternatives().get(i);
390 sources[i] = createGenerator(alternative, null, false, Uniqueness.NONE, context);
391 }
392 Class<?> javaType = descriptor.getPrimitiveType().getJavaType();
393 return new AlternativeGenerator(javaType, sources);
394 }
395
396 private static Generator<?> createByteArrayGenerator(SimpleTypeDescriptor descriptor, BeneratorContext context) {
397 Generator<Byte> byteGenerator = new AsByteGeneratorWrapper<>(new RandomIntegerGenerator(-128, 127, 1));
398 return new ByteArrayGenerator(byteGenerator,
399 DescriptorUtil.getMinLength(descriptor), DescriptorUtil.getMaxLength(descriptor, context.getDefaultsProvider()));
400 }
401
402 @SuppressWarnings({"unchecked", "rawtypes"})
403 private Generator<Timestamp> createTimestampGenerator(SimpleTypeDescriptor descriptor, Uniqueness uniqueness, BeneratorContext context) {
404 Generator<Date> source = createDateGenerator(descriptor, uniqueness, context);
405 Converter<Date, Timestamp> converter = (Converter) new AnyConverter<>(Timestamp.class);
406 return WrapperFactory.applyConverter(source, converter);
407 }
408
409 private Generator<Date> createDateGenerator(SimpleTypeDescriptor descriptor, Uniqueness uniqueness, BeneratorContext context) {
410 Date min = parseDate(descriptor, MIN, null);
411 Date max = parseDate(descriptor, MAX, null);
412 long granularity = parseDateGranularity(descriptor);
413 Distribution distribution = FactoryUtil.getDistribution(
414 descriptor.getDistribution(), uniqueness, true, context);
415 return context.getGeneratorFactory().createDateGenerator(min, max, granularity, distribution);
416 }
417
418 private static Generator<Character> createCharacterGenerator(
419 SimpleTypeDescriptor descriptor, Uniqueness uniqueness, BeneratorContext context) {
420 String pattern = descriptor.getPattern();
421 if (pattern == null) {
422 pattern = ".";
423 }
424 Locale locale = descriptor.getLocale();
425 GeneratorFactory generatorFactory = context.getGeneratorFactory();
426 return generatorFactory.createCharacterGenerator(pattern, locale, uniqueness.isUnique());
427 }
428
429 private Date parseDate(SimpleTypeDescriptor descriptor, String detailName, Date defaultDate) {
430 String detail = (String) descriptor.getDeclaredDetailValue(detailName);
431 try {
432 if (detail != null) {
433 DateFormat dateFormat = DescriptorUtil.getPatternAsDateFormat(descriptor);
434 return dateFormat.parse(detail);
435 } else {
436 return defaultDate;
437 }
438 } catch (java.text.ParseException e) {
439 logger.error("Error parsing date " + detail, e);
440 return defaultDate;
441 }
442 }
443
444 private static long parseDateGranularity(SimpleTypeDescriptor descriptor) {
445 String detail = (String) descriptor.getDeclaredDetailValue(DescriptorConstants.ATT_GRANULARITY);
446 if (detail != null) {
447 return DateString2DurationConverter.defaultInstance().convert(detail);
448 } else {
449 return 24 * 3600 * 1000L;
450 }
451 }
452
453 private static Generator<Boolean> createBooleanGenerator(SimpleTypeDescriptor descriptor, BeneratorContext context) {
454 return context.getGeneratorFactory().createBooleanGenerator(descriptor.getTrueQuota());
455 }
456
457 private static <T extends Number> Generator<T> createNumberGenerator(
458 SimpleTypeDescriptor descriptor, Class<T> targetType, Uniqueness uniqueness, BeneratorContext context) {
459 T min = DescriptorUtil.getNumberDetail(descriptor, MIN, targetType);
460 Boolean minInclusive = descriptor.isMinInclusive();
461 T max = DescriptorUtil.getNumberDetail(descriptor, MAX, targetType);
462 Boolean maxInclusive = descriptor.isMaxInclusive();
463 T granularity = DescriptorUtil.getNumberDetail(descriptor, GRANULARITY, targetType);
464 Distribution distribution = FactoryUtil.getDistribution(
465 descriptor.getDistribution(), uniqueness, false, context);
466 return context.getGeneratorFactory().createNumberGenerator(targetType, min, minInclusive, max, maxInclusive,
467 granularity, distribution, uniqueness);
468 }
469
470 private static Generator<String> createStringGenerator(SimpleTypeDescriptor descriptor, Uniqueness uniqueness, BeneratorContext context) {
471
472 Integer maxLength = null;
473 SimpleTypeDescriptor tmp = descriptor;
474 while (maxLength == null && tmp != null) {
475 maxLength = tmp.getMaxLength();
476 tmp = tmp.getParent();
477 }
478
479
480 String pattern = ToStringConverter.convert(descriptor.getDetailValue(PATTERN), null);
481
482 Integer minLength = descriptor.getMinLength();
483 int lengthGranularity = 1;
484 Distribution lengthDistribution = FactoryUtil.getDistribution(
485 descriptor.getLengthDistribution(), Uniqueness.NONE, false, context);
486 Locale locale = descriptor.getLocale();
487 GeneratorFactory factory = context.getGeneratorFactory();
488 return factory.createStringGenerator(pattern, locale, minLength, maxLength, lengthGranularity,
489 lengthDistribution, uniqueness);
490 }
491
492
493
494
495
496
497
498
499
500
501
502 @SuppressWarnings("unchecked")
503 protected static <A extends Annotation, T> Validator<T> createRestrictionValidator(
504 SimpleTypeDescriptor descriptor, boolean nullable, GeneratorFactory context) {
505 if ((descriptor.getMinLength() != null || descriptor.getMaxLength() != null) && "string".equals(descriptor.getName())) {
506 Integer minLength = DescriptorUtil.getMinLength(descriptor);
507 Integer maxLength = DescriptorUtil.getMaxLength(descriptor, context.getDefaultsProvider());
508 return (Validator<T>) new StringLengthValidator(minLength, maxLength, nullable);
509 }
510 return null;
511 }
512
513 }