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.BooleanGenerator;
35  import com.rapiddweller.benerator.primitive.IncrementalStringGenerator;
36  import com.rapiddweller.benerator.primitive.RandomVarLengthStringGenerator;
37  import com.rapiddweller.benerator.primitive.UniqueScrambledStringGenerator;
38  import com.rapiddweller.benerator.sample.AttachedWeightSampleGenerator;
39  import com.rapiddweller.benerator.sample.ConstantGenerator;
40  import com.rapiddweller.benerator.sample.OneShotGenerator;
41  import com.rapiddweller.benerator.sample.SampleGenerator;
42  import com.rapiddweller.benerator.wrapper.AlternativeGenerator;
43  import com.rapiddweller.benerator.wrapper.CompositeStringGenerator;
44  import com.rapiddweller.benerator.wrapper.GeneratorChain;
45  import com.rapiddweller.benerator.wrapper.IteratingGenerator;
46  import com.rapiddweller.benerator.wrapper.SimpleMultiSourceArrayGenerator;
47  import com.rapiddweller.benerator.wrapper.UniqueMultiSourceArrayGenerator;
48  import com.rapiddweller.benerator.wrapper.WrapperFactory;
49  import com.rapiddweller.common.ConfigurationError;
50  import com.rapiddweller.common.converter.ConverterManager;
51  import com.rapiddweller.common.converter.ToStringConverter;
52  import com.rapiddweller.common.iterator.ArrayIterable;
53  import com.rapiddweller.model.data.Uniqueness;
54  import com.rapiddweller.script.DatabeneScriptParser;
55  import com.rapiddweller.script.WeightedSample;
56  
57  import java.util.Collection;
58  import java.util.Set;
59  
60  /**
61   * {@link GeneratorFactory} implementation that generates docile data in order to avoid functional failures
62   * and combines them randomly and repetitively for generating large data volumes. Its primary purpose is
63   * data generation for performance tests.<br/>
64   * <br/>
65   * Created: 04.07.2011 09:34:34
66   *
67   * @author Volker Bergmann
68   * @since 0.7.0
69   */
70  public class StochasticGeneratorFactory extends GeneratorFactory {
71  
72    /**
73     * Instantiates a new Stochastic generator factory.
74     */
75    public StochasticGeneratorFactory() {
76      super(new GentleDefaultsProvider());
77    }
78  
79    @Override
80    public <T> Generator<T> createAlternativeGenerator(Class<T> targetType, Generator<T>[] sources,
81                                                       Uniqueness uniqueness) {
82      if (uniqueness == Uniqueness.ORDERED) {
83        return new GeneratorChain<>(targetType, uniqueness.isUnique(), sources);
84      } else {
85        return new AlternativeGenerator<>(targetType, sources);
86      }
87    }
88  
89    @Override
90    public <T> Generator<T[]> createCompositeArrayGenerator(
91        Class<T> componentType, Generator<T>[] sources, Uniqueness uniqueness) {
92      if (uniqueness.isUnique()) {
93        return new UniqueMultiSourceArrayGenerator<>(componentType, sources);
94      } else {
95        return new SimpleMultiSourceArrayGenerator<>(componentType, sources);
96      }
97    }
98  
99    @Override
100   public <T> Generator<T> createSampleGenerator(Collection<T> values,
101                                                 Class<T> generatedType, boolean unique) {
102     SampleGenerator<T> generator = new SampleGenerator<>(generatedType, values);
103     generator.setUnique(unique);
104     return generator;
105   }
106 
107   @Override
108   @SuppressWarnings("unchecked")
109   public <T> Generator<T> createFromWeightedLiteralList(String valueSpec, Class<T> targetType,
110                                                         Distribution distribution, boolean unique) {
111     WeightedSample<T>[] samples = (WeightedSample<T>[]) DatabeneScriptParser.parseWeightedLiteralList(valueSpec);
112     if (distribution == null && !unique && weightsUsed(samples)) {
113       AttachedWeightSampleGenerator<T> generator = new AttachedWeightSampleGenerator<>(targetType);
114       for (WeightedSample<T> sample : samples) {
115         if (sample.getValue() == null) {
116           throw new ConfigurationError("null is not supported in values='...', drop it from the list and " +
117               "use a nullQuota instead");
118         }
119         generator.addSample(sample.getValue(), sample.getWeight());
120       }
121       return generator;
122     } else {
123       String[] values = new String[samples.length];
124       for (int i = 0; i < samples.length; i++) {
125         T rawValue = samples[i].getValue();
126         String value = ToStringConverter.convert(rawValue, null);
127         values[i] = value;
128       }
129       IteratingGenerator<String> source = new IteratingGenerator<>(
130           new ArrayIterable<>(values, String.class));
131       if (distribution == null) {
132         distribution = SequenceManager.RANDOM_SEQUENCE;
133       }
134       Generator<T> gen = WrapperFactory.applyConverter(source, ConverterManager.getInstance().createConverter(
135           String.class, targetType));
136       return distribution.applyTo(gen, unique);
137     }
138   }
139 
140   @Override
141   public Generator<Boolean> createBooleanGenerator(Double trueQuota) {
142     return new BooleanGenerator(trueQuota != null ? trueQuota : 0.5);
143   }
144 
145   private static boolean weightsUsed(WeightedSample<?>[] samples) {
146     for (WeightedSample<?> sample : samples) {
147       if (sample.getWeight() != 1) {
148         return true;
149       }
150     }
151     return false;
152   }
153 
154   @Override
155   public NonNullGenerator<String> createStringGenerator(Set<Character> chars,
156                                                         Integer minLength, Integer maxLength, int lengthGranularity, Distribution lengthDistribution,
157                                                         Uniqueness uniqueness) {
158     if (uniqueness == Uniqueness.ORDERED) {
159       return new IncrementalStringGenerator(chars, minLength, maxLength, lengthGranularity);
160     } else if (uniqueness.isUnique()) {
161       return new UniqueScrambledStringGenerator(chars, minLength, maxLength);
162     } else {
163       return new RandomVarLengthStringGenerator(
164           chars, minLength, maxLength, lengthGranularity, lengthDistribution);
165     }
166   }
167 
168   @Override
169   public Generator<?> applyNullSettings(Generator<?> source, Boolean nullable, Double nullQuota) {
170     if (nullQuota == null) {
171       if (nullable == null) {
172         nullable = defaultsProvider.defaultNullable();
173       }
174       nullQuota = (nullable ? (defaultsProvider.defaultNullQuota() != 1 ? defaultsProvider.defaultNullQuota() : 0) : 0);
175     }
176     return WrapperFactory.injectNulls(source, nullQuota);
177   }
178 
179   @Override
180   public <T> Generator<T> createSingleValueGenerator(T value, boolean unique) {
181     if (unique) {
182       return new OneShotGenerator<>(value);
183     } else {
184       return new ConstantGenerator<>(value);
185     }
186   }
187 
188   @Override
189   protected double defaultTrueQuota() {
190     return 0.5;
191   }
192 
193   @Override
194   protected Distribution defaultLengthDistribution(Uniqueness uniqueness, boolean required) {
195     switch (uniqueness) {
196       case ORDERED:
197         return SequenceManager.STEP_SEQUENCE;
198       case SIMPLE:
199         return SequenceManager.EXPAND_SEQUENCE;
200       default:
201         if (required) {
202           return SequenceManager.RANDOM_SEQUENCE;
203         } else {
204           return null;
205         }
206     }
207   }
208 
209   @Override
210   public Distribution defaultDistribution(Uniqueness uniqueness) {
211     if (uniqueness == null) {
212       return SequenceManager.STEP_SEQUENCE;
213     }
214     switch (uniqueness) {
215       case ORDERED:
216         return SequenceManager.STEP_SEQUENCE;
217       case SIMPLE:
218         return SequenceManager.EXPAND_SEQUENCE;
219       default:
220         return SequenceManager.RANDOM_SEQUENCE;
221     }
222   }
223 
224   @Override
225   protected boolean defaultUnique() {
226     return false;
227   }
228 
229   @Override
230   public <T> Generator<T> createNullGenerator(Class<T> generatedType) {
231     return new ConstantGenerator<>(null, generatedType);
232   }
233 
234   @SuppressWarnings("unchecked")
235   @Override
236   public NonNullGenerator<String> createCompositeStringGenerator(
237       GeneratorProvider<?> partGeneratorProvider, int minParts, int maxParts, Uniqueness uniqueness) {
238     AlternativeGenerator<String> result = new AlternativeGenerator<>(String.class);
239     for (int partCount = minParts; partCount <= maxParts; partCount++) {
240       Generator<String>[] sources = new Generator[partCount];
241       for (int i = 0; i < partCount; i++) {
242         sources[i] = WrapperFactory.asStringGenerator(partGeneratorProvider.create());
243       }
244       result.addSource(new CompositeStringGenerator(uniqueness.isUnique(), sources));
245     }
246     return WrapperFactory.asNonNullGenerator(result);
247   }
248 
249 }