View Javadoc
1   /*
2    * (c) Copyright 2006-2020 by rapiddweller GmbH & Volker Bergmann. All rights reserved.
3    *
4    * Redistribution and use in source and binary forms, with or without
5    * modification, is permitted under the terms of the
6    * GNU General Public License.
7    *
8    * For redistributing this software or a derivative work under a license other
9    * than the GPL-compatible Free Software License as defined by the Free
10   * Software Foundation or approved by OSI, you must first obtain a commercial
11   * license to this software product from rapiddweller GmbH & Volker Bergmann.
12   *
13   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14   * WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS,
15   * REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF
16   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE
17   * HEREBY EXCLUDED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24   * POSSIBILITY OF SUCH DAMAGE.
25   */
26  
27  package com.rapiddweller.benerator.factory;
28  
29  import com.rapiddweller.benerator.Generator;
30  import com.rapiddweller.benerator.GeneratorProvider;
31  import com.rapiddweller.benerator.NonNullGenerator;
32  import com.rapiddweller.benerator.distribution.Distribution;
33  import com.rapiddweller.benerator.distribution.SequenceManager;
34  import com.rapiddweller.benerator.primitive.CharacterGenerator;
35  import com.rapiddweller.benerator.primitive.datetime.DateGenerator;
36  import com.rapiddweller.benerator.sample.AttachedWeightSampleGenerator;
37  import com.rapiddweller.benerator.sample.ConstantGenerator;
38  import com.rapiddweller.benerator.sample.SequenceGenerator;
39  import com.rapiddweller.benerator.wrapper.WrapperFactory;
40  import com.rapiddweller.common.Assert;
41  import com.rapiddweller.common.ConfigurationError;
42  import com.rapiddweller.common.TimeUtil;
43  import com.rapiddweller.common.validator.StringLengthValidator;
44  import com.rapiddweller.format.regex.RegexParser;
45  import com.rapiddweller.format.regex.RegexPart;
46  import com.rapiddweller.model.data.Uniqueness;
47  import com.rapiddweller.script.WeightedSample;
48  
49  import java.util.Calendar;
50  import java.util.Collection;
51  import java.util.Date;
52  import java.util.Locale;
53  import java.util.Objects;
54  import java.util.Set;
55  
56  /**
57   * Provides factory methods for generators.<br/>
58   * <br/>
59   * Created: 23.08.2006 21:44:27
60   *
61   * @author Volker Bergmann
62   * @since 0.1
63   */
64  public abstract class GeneratorFactory {
65  
66    /**
67     * The Defaults provider.
68     */
69    protected DefaultsProvider defaultsProvider;
70  
71    /**
72     * Instantiates a new Generator factory.
73     */
74    protected GeneratorFactory() {
75      this(null);
76    }
77  
78    /**
79     * Instantiates a new Generator factory.
80     *
81     * @param defaultsProvider the defaults provider
82     */
83    protected GeneratorFactory(DefaultsProvider defaultsProvider) {
84      this.defaultsProvider = defaultsProvider;
85    }
86  
87    /**
88     * Gets defaults provider.
89     *
90     * @return the defaults provider
91     */
92    public DefaultsProvider getDefaultsProvider() {
93      return defaultsProvider;
94    }
95  
96    /**
97     * Sets defaults provider.
98     *
99     * @param defaultsProvider the defaults provider
100    */
101   public void setDefaultsProvider(DefaultsProvider defaultsProvider) {
102     this.defaultsProvider = defaultsProvider;
103   }
104 
105 
106   /**
107    * Create alternative generator generator.
108    *
109    * @param <T>        the type parameter
110    * @param targetType the target type
111    * @param sources    the sources
112    * @param uniqueness the uniqueness
113    * @return the generator
114    */
115   public abstract <T> Generator<T> createAlternativeGenerator(Class<T> targetType, Generator<T>[] sources,
116                                                               Uniqueness uniqueness);
117 
118   // boolean generator -----------------------------------------------------------------------------------------------
119 
120   /**
121    * Creates a generator for boolean values with a trueQuota [0-1]
122    *
123    * @param trueQuota a value from 0 to 1, indicating the quota of true values to generate among the non-null values
124    * @return a Boolean generator of the desired characteristics
125    */
126   public Generator<Boolean> createBooleanGenerator(Double trueQuota) {
127     SequenceGenerator<Boolean> generator = new SequenceGenerator<>(Boolean.class);
128     if (trueQuota == null || trueQuota < 1) {
129       generator.addValue(false);
130     }
131     if (trueQuota == null || trueQuota > 0) {
132       generator.addValue(true);
133     }
134     return generator;
135   }
136 
137   // number generators -----------------------------------------------------------------------------------------------
138 
139   /**
140    * Creates a generator for numbers.
141    *
142    * @param <T>          the type parameter
143    * @param numberType   the number type, e.g. java.lang.Integer
144    * @param min          the minimum number to generate
145    * @param minInclusive the min inclusive
146    * @param max          the maximum number to generate
147    * @param maxInclusive the max inclusive
148    * @param granularity  the resolution to use in number generation.
149    * @param distribution The Sequence of WeightFunction to use for generation
150    * @param uniqueness   the uniqueness
151    * @return a Number generator of the desired characteristics
152    */
153   public <T extends Number> NonNullGenerator<T> createNumberGenerator(
154       Class<T> numberType, T min, Boolean minInclusive, T max, Boolean maxInclusive, T granularity,
155       Distribution distribution, Uniqueness uniqueness) {
156     Assert.notNull(numberType, "numberType");
157     if (min != null && min.equals(max)) {
158       return WrapperFactory.asNonNullGenerator(new ConstantGenerator<>(min));
159     }
160     if (min == null) {
161       min = defaultsProvider.defaultMin(numberType);
162     }
163     if (granularity == null) {
164       granularity = defaultsProvider.defaultGranularity(numberType);
165     }
166     if (distribution == null) {
167       if (Uniqueness.ORDERED == uniqueness) {
168         distribution = SequenceManager.STEP_SEQUENCE;
169       } else {
170         distribution = defaultDistribution(uniqueness);
171       }
172     }
173     return distribution.createNumberGenerator(numberType, min, max, granularity, uniqueness.isUnique());
174   }
175 
176   // sample source ------------------------------------------------------------------------------------------------
177 
178   /**
179    * Create from weighted literal list generator.
180    *
181    * @param <T>          the type parameter
182    * @param valueSpec    the value spec
183    * @param targetType   the target type
184    * @param distribution the distribution
185    * @param unique       the unique
186    * @return the generator
187    */
188   public abstract <T> Generator<T> createFromWeightedLiteralList(String valueSpec, Class<T> targetType,
189                                                                  Distribution distribution, boolean unique);
190 
191   /**
192    * Create sample generator generator.
193    *
194    * @param <T>           the type parameter
195    * @param values        the values
196    * @param generatedType the generated type
197    * @param unique        the unique
198    * @return the generator
199    */
200   public abstract <T> Generator<T> createSampleGenerator(Collection<T> values, Class<T> generatedType, boolean unique);
201 
202   /**
203    * Creates a generator that chooses from a set of samples, using an individual weight for each sample.
204    *
205    * @param <T>        the type parameter
206    * @param samples    A collection of sample values
207    * @param targetType the target type
208    * @return a generator of the desired characteristics
209    */
210   public <T> Generator<T> createWeightedSampleGenerator(Collection<WeightedSample<T>> samples, Class<T> targetType) {
211     AttachedWeightSampleGenerator<T> generator = new AttachedWeightSampleGenerator<>(targetType);
212     for (WeightedSample<T> sample : samples) {
213       generator.addSample(sample.getValue(), sample.getWeight());
214     }
215     return generator;
216   }
217 
218   // date source --------------------------------------------------------------------------------------------------
219 
220   /**
221    * Creates a Date generator that generates random dates.
222    *
223    * @param min          the earliest Date to generate
224    * @param max          the latest Date to generate
225    * @param granularity  the time resolution of dates in milliseconds
226    * @param distribution the distribution to use
227    * @return a generator of the desired characteristics
228    */
229   public Generator<Date> createDateGenerator(
230       Date min, Date max, long granularity, Distribution distribution) {
231     if (min == null) {
232       if (max == null) {
233         min = TimeUtil.date(1970, 0, 1);
234         max = new Date();
235       } else {
236         min = TimeUtil.add(max, Calendar.DATE, -365);
237       }
238     } else if (max == null) {
239       max = TimeUtil.add(min, Calendar.DATE, 365);
240     }
241     return new DateGenerator(min, max, granularity, distribution);
242   }
243 
244   // text generators -------------------------------------------------------------------------------------------------
245 
246   /**
247    * Creates a Character generator that creates characters of a Locale which match a regular expression.
248    *
249    * @param pattern the regular expression that indicates the available range of values.                If null, any letters of the specified locale will be used
250    * @param locale  the locale to use for '\w' evaluation
251    * @param unique  flag indicating if character generation should be unique
252    * @return a generator of the desired characteristics
253    */
254   public Generator<Character> createCharacterGenerator(String pattern, Locale locale, boolean unique) {
255     Set<Character> chars = FactoryUtil.fullLocaleCharSet(pattern, locale);
256     if (unique) {
257       return new SequenceGenerator<>(Character.class, chars);
258     } else {
259       return new CharacterGenerator(chars);
260     }
261   }
262 
263   /**
264    * Creates a character generator that creates values from a collection of characters
265    *
266    * @param characters the set of characters to choose from
267    * @return a generator of the desired characteristics
268    */
269   public NonNullGenerator<Character> createCharacterGenerator(Set<Character> characters) {
270     return new CharacterGenerator(defaultSubSet(characters));
271   }
272 
273   /**
274    * Create string generator generator.
275    *
276    * @param pattern            the pattern
277    * @param locale             the locale
278    * @param minLength          the min length
279    * @param maxLength          the max length
280    * @param lengthGranularity  the length granularity
281    * @param lengthDistribution the length distribution
282    * @param uniqueness         the uniqueness
283    * @return the generator
284    */
285   public Generator<String> createStringGenerator(String pattern,
286                                                  Locale locale, Integer minLength, Integer maxLength, int lengthGranularity,
287                                                  Distribution lengthDistribution, Uniqueness uniqueness) {
288     if (pattern != null) {
289       RegexPart regex = new RegexParser().parseRegex(pattern);
290       int regexMinLength = regex.minLength();
291       Integer regexMaxLength = regex.maxLength();
292       if (maxLength == null) {
293         maxLength = Objects.requireNonNullElseGet(regexMaxLength, () -> Math.max(regexMinLength * 2, defaultsProvider.defaultMaxLength()));
294       }
295 
296       if (minLength == null) {
297         minLength = regexMinLength;
298       }
299     } else {
300       pattern = "[A-Z]*";
301       if (maxLength == null) {
302         maxLength = defaultsProvider.defaultMaxLength();
303       }
304       if (minLength == null) {
305         minLength = defaultsProvider.defaultMinLength();
306       }
307     }
308     if (lengthDistribution != null) {
309       Set<Character> chars = new RegexParser(locale).parseSingleChar(pattern).getCharSet().getSet();
310       return createStringGenerator(
311           chars, minLength, maxLength, lengthGranularity, lengthDistribution, uniqueness);
312     }
313     if (locale == null) {
314       locale = FactoryUtil.defaultLocale();
315     }
316     return createRegexStringGenerator(pattern, minLength, maxLength, uniqueness);
317   }
318 
319   /**
320    * Create string generator non null generator.
321    *
322    * @param chars              the chars
323    * @param minLength          the min length
324    * @param maxLength          the max length
325    * @param lengthGranularity  the length granularity
326    * @param lengthDistribution the length distribution
327    * @param uniqueness         the uniqueness
328    * @return the non null generator
329    */
330   public abstract NonNullGenerator<String> createStringGenerator(Set<Character> chars,
331                                                                  Integer minLength, Integer maxLength, int lengthGranularity,
332                                                                  Distribution lengthDistribution,
333                                                                  Uniqueness uniqueness);
334 
335   /**
336    * Create composite string generator non null generator.
337    *
338    * @param partGeneratorProvider the part generator provider
339    * @param minParts              the min parts
340    * @param maxParts              the max parts
341    * @param uniqueness            the uniqueness
342    * @return the non null generator
343    */
344   public abstract NonNullGenerator<String> createCompositeStringGenerator(
345       GeneratorProvider<?> partGeneratorProvider, int minParts, int maxParts, Uniqueness uniqueness);
346 
347   /**
348    * Creates a generator that produces Strings which match a regular expression in a locale
349    *
350    * @param pattern    the regular expression
351    * @param minLength  the minimum length of the products
352    * @param maxLength  the maximum length of the products
353    * @param uniqueness the uniqueness
354    * @return a generator of the desired characteristics
355    * @throws ConfigurationError if something is wrong configured
356    */
357   public NonNullGenerator<String> createRegexStringGenerator(String pattern, int minLength, Integer maxLength,
358                                                              Uniqueness uniqueness) throws ConfigurationError {
359     NonNullGenerator<String> generator = RegexGeneratorFactory.create(pattern, minLength, maxLength, uniqueness, this);
360     StringLengthValidator validator = new StringLengthValidator(minLength, maxLength);
361     return WrapperFactory.asNonNullGenerator(WrapperFactory.applyValidator(validator, generator));
362   }
363 
364   // collection generators -------------------------------------------------------------------------------------------
365 
366   /**
367    * Creates a generator that reads products of an array of generators and combines them in an array.
368    *
369    * @param <T>           the type parameter
370    * @param componentType the component type
371    * @param sources       the source generators
372    * @param uniqueness    the uniqueness
373    * @return a generator of the desired characteristics
374    */
375   public abstract <T> Generator<T[]> createCompositeArrayGenerator(
376       Class<T> componentType, Generator<T>[] sources, Uniqueness uniqueness);
377 
378   // wrappers --------------------------------------------------------------------------------------------------------
379 
380   /**
381    * Creates a generator that returns a single value.
382    *
383    * @param <T>    the type parameter
384    * @param value  the value to return
385    * @param unique the unique
386    * @return a generator that returns a constant value.
387    */
388   public abstract <T> Generator<T> createSingleValueGenerator(T value, boolean unique);
389 
390   /**
391    * Apply null settings generator.
392    *
393    * @param source    the source
394    * @param nullable  the nullable
395    * @param nullQuota the null quota
396    * @return the generator
397    */
398   public abstract Generator<?> applyNullSettings(Generator<?> source, Boolean nullable, Double nullQuota);
399 
400   /**
401    * Create null generator generator.
402    *
403    * @param <T>           the type parameter
404    * @param generatedType the generated type
405    * @return the generator
406    */
407   public abstract <T> Generator<T> createNullGenerator(Class<T> generatedType);
408 
409 
410   // default setting providers ---------------------------------------------------------------------------------------
411 
412   /**
413    * Default sub set set.
414    *
415    * @param characters the characters
416    * @return the set
417    */
418   public Set<Character> defaultSubSet(Set<Character> characters) {
419     return characters;
420   }
421 
422   /**
423    * Default unique boolean.
424    *
425    * @return the boolean
426    */
427   protected abstract boolean defaultUnique();
428 
429   /**
430    * Default true quota double.
431    *
432    * @return the double
433    */
434   protected abstract double defaultTrueQuota();
435 
436   /**
437    * Default distribution distribution.
438    *
439    * @param uniqueness the uniqueness
440    * @return the distribution
441    */
442   public abstract Distribution defaultDistribution(Uniqueness uniqueness);
443 
444   /**
445    * Default length distribution distribution.
446    *
447    * @param uniqueness the uniqueness
448    * @param required   the required
449    * @return the distribution
450    */
451   protected abstract Distribution defaultLengthDistribution(Uniqueness uniqueness, boolean required);
452 
453 }