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.domain.person;
28  
29  import com.rapiddweller.benerator.Generator;
30  import com.rapiddweller.benerator.GeneratorContext;
31  import com.rapiddweller.benerator.NonNullGenerator;
32  import com.rapiddweller.benerator.dataset.DatasetBasedGenerator;
33  import com.rapiddweller.benerator.dataset.DatasetUtil;
34  import com.rapiddweller.benerator.primitive.BooleanGenerator;
35  import com.rapiddweller.benerator.wrapper.CompositeGenerator;
36  import com.rapiddweller.benerator.wrapper.ProductWrapper;
37  import com.rapiddweller.common.Converter;
38  import com.rapiddweller.domain.address.Country;
39  
40  import java.util.HashMap;
41  import java.util.Locale;
42  import java.util.Map;
43  
44  import static com.rapiddweller.benerator.util.GeneratorUtil.generateNonNull;
45  import static com.rapiddweller.benerator.util.GeneratorUtil.generateNullable;
46  
47  /**
48   * Generates {@link Person} beans.<br/>
49   * <br/>
50   * Created: 09.06.2006 21:45:13
51   *
52   * @author Volker Bergmann
53   * @since 0.1
54   */
55  public class PersonGenerator extends CompositeGenerator<Person>
56      implements DatasetBasedGenerator<Person>, NonNullGenerator<Person> {
57  
58    private static final String REGION_NESTING =
59        "com/rapiddweller/dataset/region";
60  
61    private String datasetName;
62    private Locale locale;
63  
64    private final GenderGenerator genderGen;
65    private GivenNameGenerator maleGivenNameGen;
66    private GivenNameGenerator femaleGivenNameGen;
67    private BooleanGenerator secondNameTest;
68    private FamilyNameGenerator familyNameGen;
69    private final Map<String, Converter<String, String>>
70        femaleFamilyNameConverters;
71    private AcademicTitleGenerator acadTitleGen;
72    private NobilityTitleGenerator maleNobilityTitleGen;
73    private NobilityTitleGenerator femaleNobilityTitleGen;
74    private SalutationProvider salutationProvider;
75  
76    private final BirthDateGenerator birthDateGenerator;
77    private EMailAddressBuilder emailGenerator;
78  
79    // constructors ----------------------------------------------------------------------------------------------------
80  
81    /**
82     * Instantiates a new Person generator.
83     */
84    public PersonGenerator() {
85      this(Country.getDefault().getIsoCode(), Locale.getDefault());
86    }
87  
88    /**
89     * Instantiates a new Person generator.
90     *
91     * @param datasetName the dataset name
92     */
93    public PersonGenerator(String datasetName) {
94      this(datasetName, DatasetUtil.defaultLanguageForRegion(datasetName));
95    }
96  
97    /**
98     * Instantiates a new Person generator.
99     *
100    * @param datasetName the dataset name
101    * @param locale      the locale
102    */
103   public PersonGenerator(String datasetName, Locale locale) {
104     super(Person.class);
105     logger.debug(
106         "Instantiating PersonGenerator with dataset '{}' and locale '{}'",
107         datasetName, locale);
108     this.datasetName = datasetName;
109     this.locale = locale;
110     genderGen = registerComponent(new GenderGenerator(0.5));
111     birthDateGenerator = registerComponent(new BirthDateGenerator(15, 105));
112     this.femaleFamilyNameConverters = new HashMap<>();
113   }
114 
115   // properties ------------------------------------------------------------------------------------------------------
116 
117   /**
118    * Sets min age years.
119    *
120    * @param minAgeYears the min age years
121    */
122   public void setMinAgeYears(int minAgeYears) {
123     birthDateGenerator.setMinAgeYears(minAgeYears);
124   }
125 
126   /**
127    * Sets max age years.
128    *
129    * @param maxAgeYears the max age years
130    */
131   public void setMaxAgeYears(int maxAgeYears) {
132     birthDateGenerator.setMaxAgeYears(maxAgeYears);
133   }
134 
135   /**
136    * Gets female quota.
137    *
138    * @return the female quota
139    */
140   public double getFemaleQuota() {
141     return genderGen.getFemaleQuota();
142   }
143 
144   /**
145    * Sets female quota.
146    *
147    * @param femaleQuota the female quota
148    */
149   public void setFemaleQuota(double femaleQuota) {
150     this.genderGen.setFemaleQuota(femaleQuota);
151   }
152 
153   /**
154    * Gets noble quota.
155    *
156    * @return the noble quota
157    */
158   public double getNobleQuota() {
159     return maleNobilityTitleGen.getNobleQuota();
160   }
161 
162   /**
163    * Sets noble quota.
164    *
165    * @param nobleQuota the noble quota
166    */
167   public void setNobleQuota(double nobleQuota) {
168     maleNobilityTitleGen.setNobleQuota(nobleQuota);
169     femaleNobilityTitleGen.setNobleQuota(nobleQuota);
170   }
171 
172   /**
173    * Gets locale.
174    *
175    * @return the locale
176    */
177   public Locale getLocale() {
178     return acadTitleGen.getLocale();
179   }
180 
181   /**
182    * Sets locale.
183    *
184    * @param locale the locale
185    */
186   public void setLocale(Locale locale) {
187     this.locale = locale;
188   }
189 
190   @Override
191   public String getDataset() {
192     return datasetName;
193   }
194 
195   // DatasetBasedGenerator interface implementation ------------------------------------------------------------------
196 
197   /**
198    * Sets dataset.
199    *
200    * @param datasetName the dataset name
201    */
202   public void setDataset(String datasetName) {
203     this.datasetName = datasetName;
204   }
205 
206   @Override
207   public String getNesting() {
208     return REGION_NESTING;
209   }
210 
211   @Override
212   public Person generateForDataset(String datasetToUse) {
213     assertInitialized();
214     Personon/Person.html#Person">Person person = new Person(acadTitleGen.getLocale());
215     person.setGender(generateNonNull(genderGen));
216     GivenNameGenerator givenNameGenerator
217         = (Gender.MALE.equals(person.getGender()) ? maleGivenNameGen :
218         femaleGivenNameGen);
219     String givenName = givenNameGenerator.generateForDataset(datasetToUse);
220     person.setGivenName(givenName);
221     if (generateNullable(secondNameTest)) {
222       do {
223         person.setSecondGivenName(
224             givenNameGenerator.generateForDataset(datasetToUse));
225       } while (person.getGivenName().equals(person.getSecondGivenName()));
226     }
227     String familyName = familyNameGen.generateForDataset(datasetToUse);
228     if (Gender.FEMALE.equals(person.getGender())) {
229       familyName = getFemaleFamilyNameConverter(datasetToUse)
230           .convert(familyName);
231     }
232     person.setFamilyName(familyName);
233     person.setSalutation(salutationProvider.salutation(person.getGender()));
234     person.setAcademicTitle(generateNullable(acadTitleGen));
235     NobilityTitleGenerator nobTitleGenerator
236         =
237         (Gender.MALE.equals(person.getGender()) ? maleNobilityTitleGen :
238             femaleNobilityTitleGen);
239     person.setNobilityTitle(generateNullable(nobTitleGenerator));
240     person.setBirthDate(generateNullable(birthDateGenerator));
241     person.setEmail(emailGenerator.generate(givenName, familyName));
242     return person;
243   }
244 
245   // Generator interface ---------------------------------------------------------------------------------------------
246 
247   @Override
248   public synchronized void init(GeneratorContext context) {
249     secondNameTest = registerAndInitComponent(new BooleanGenerator(0.2));
250     genderGen.init(context);
251     birthDateGenerator.init(context);
252     acadTitleGen =
253         registerAndInitComponent(new AcademicTitleGenerator(locale));
254     acadTitleGen.setLocale(locale);
255     maleNobilityTitleGen = registerAndInitComponent(
256         new NobilityTitleGenerator(Gender.MALE, locale));
257     femaleNobilityTitleGen = registerAndInitComponent(
258         new NobilityTitleGenerator(Gender.FEMALE, locale));
259     salutationProvider = new SalutationProvider(locale);
260 
261     try {
262       initMembersWithDataset(context);
263     } catch (RuntimeException e) {
264       Country fallBackCountry = Country.getFallback();
265       if (!fallBackCountry.getIsoCode().equals(datasetName)) {
266         logger.error("Error initializing " + getClass().getSimpleName(),
267             e);
268         logger.error("Cannot generate persons for " + datasetName +
269             ", falling back to " + fallBackCountry);
270         this.datasetName = fallBackCountry.getIsoCode();
271         initMembersWithDataset(context);
272       } else {
273         throw e;
274       }
275     }
276     super.init(context);
277   }
278 
279   /**
280    * Register and init component t.
281    *
282    * @param <T>       the type parameter
283    * @param <U>       the type parameter
284    * @param generator the generator
285    * @return the t
286    */
287   protected <T extends Generator<U>, U> T registerAndInitComponent(
288       T generator) {
289     registerComponent(generator);
290     generator.init(context);
291     return generator;
292   }
293 
294   @Override
295   public ProductWrapper<Person> generate(ProductWrapper<Person> wrapper) {
296     String usedDataset = randomDataset();
297     Person person = generateForDataset(usedDataset);
298     return wrapper.wrap(person).setTag(REGION_NESTING, usedDataset);
299   }
300 
301   @Override
302   public Person generate() {
303     return generateForDataset(randomDataset());
304   }
305 
306   // private helpers -------------------------------------------------------------------------------------------------
307 
308   private String randomDataset() {
309     return maleGivenNameGen.generate(new ProductWrapper<>())
310         .getTag(DatasetUtil.REGION_NESTING);
311   }
312 
313   private Converter<String, String> getFemaleFamilyNameConverter(
314       String usedDataset) {
315     Converter<String, String> result =
316         femaleFamilyNameConverters.get(usedDataset);
317     if (result == null) {
318       result = new FemaleFamilyNameConverter(datasetName);
319       femaleFamilyNameConverters.put(usedDataset, result);
320     }
321     return result;
322   }
323 
324   private void initMembersWithDataset(GeneratorContext context) {
325     maleGivenNameGen = registerAndInitComponent(
326         new GivenNameGenerator(datasetName, Gender.MALE));
327     femaleGivenNameGen = registerAndInitComponent(
328         new GivenNameGenerator(datasetName, Gender.FEMALE));
329     familyNameGen =
330         registerAndInitComponent(new FamilyNameGenerator(datasetName));
331     emailGenerator = new EMailAddressBuilder(datasetName);
332     emailGenerator.init(context);
333   }
334 
335   // java.lang.Object overrides --------------------------------------------------------------------------------------
336 
337   @Override
338   public String toString() {
339     return getClass().getSimpleName();
340   }
341 
342 }