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.dataset;
28  
29  import com.rapiddweller.benerator.GeneratorContext;
30  import com.rapiddweller.benerator.InvalidGeneratorSetupException;
31  import com.rapiddweller.benerator.WeightedGenerator;
32  import com.rapiddweller.benerator.util.RandomUtil;
33  import com.rapiddweller.benerator.wrapper.GeneratorProxy;
34  import com.rapiddweller.benerator.wrapper.ProductWrapper;
35  
36  import java.util.HashSet;
37  import java.util.Set;
38  
39  /**
40   * Abstract implementation of the {@link DatasetBasedGenerator} interface.
41   * It is configured with 'nesting' and 'dataset'. Depending on the type of
42   * the dataset (atomic or composite), it initializes a delegate instance
43   * of a {@link DatasetBasedGenerator}, either a {@link CompositeDatasetGenerator}
44   * or an {@link AtomicDatasetGenerator}. For the dfinition of custom
45   * {@link DatasetBasedGenerator}s, inherit from this class and implement
46   * the abstract method {@link #createAtomicDatasetGenerator(Dataset, boolean)}.
47   * All dataset recognition and handling and data generation will be handled
48   * automatically.<br/><br/>
49   * Created: 10.03.2011 10:44:58
50   *
51   * @param <E> the type parameter
52   * @author Volker Bergmann
53   * @since 0.6.6
54   */
55  public abstract class AbstractDatasetGenerator<E> extends GeneratorProxy<E> implements DatasetBasedGenerator<E> {
56  
57    /**
58     * The Supported datasets.
59     */
60    protected final Set<String> supportedDatasets;
61    /**
62     * The Fallback.
63     */
64    protected final boolean fallback;
65    /**
66     * The Nesting.
67     */
68    protected String nesting;
69    /**
70     * The Dataset name.
71     */
72    protected String datasetName;
73    /**
74     * The Total weight.
75     */
76    protected double totalWeight;
77  
78    // constructor -----------------------------------------------------------------------------------------------------
79  
80    /**
81     * Instantiates a new Abstract dataset generator.
82     *
83     * @param generatedType the generated type
84     * @param nesting       the nesting
85     * @param datasetName   the dataset name
86     * @param fallback      the fallback
87     */
88    public AbstractDatasetGenerator(Class<E> generatedType, String nesting, String datasetName, boolean fallback) {
89      super(generatedType);
90      this.nesting = nesting;
91      this.datasetName = datasetName;
92      this.fallback = fallback;
93      this.supportedDatasets = new HashSet<>();
94      this.supportedDatasets.add(datasetName);
95      this.totalWeight = 0;
96    }
97  
98    /**
99     * Supports dataset boolean.
100    *
101    * @param datasetName the dataset name
102    * @return the boolean
103    */
104   public boolean supportsDataset(String datasetName) {
105     return supportedDatasets.contains(datasetName);
106   }
107 
108   // DatasetBasedGenerator interface implementation ------------------------------------------------------------------
109 
110   @Override
111   public String getNesting() {
112     return nesting;
113   }
114 
115   /**
116    * Sets nesting.
117    *
118    * @param nesting the nesting
119    */
120   public void setNesting(String nesting) {
121     this.nesting = nesting;
122   }
123 
124   @Override
125   public String getDataset() {
126     return datasetName;
127   }
128 
129   /**
130    * Sets dataset.
131    *
132    * @param datasetName the dataset name
133    */
134   public void setDataset(String datasetName) {
135     this.datasetName = datasetName;
136     this.supportedDatasets.clear();
137     this.supportedDatasets.add(datasetName);
138   }
139 
140   /**
141    * Gets weight.
142    *
143    * @return the weight
144    */
145   public double getWeight() {
146     return totalWeight;
147   }
148 
149   @Override
150   public synchronized void init(GeneratorContext context) {
151     Dataset dataset = DatasetUtil.getDataset(nesting, datasetName);
152     setSource(createDatasetGenerator(dataset, true, fallback));
153     super.init(context);
154   }
155 
156   @Override
157   public E generateForDataset(String requestedDataset) {
158     DatasetBasedGenerator<E> sourceGen = getSource();
159     if (sourceGen instanceof CompositeDatasetGenerator) {
160       return sourceGen.generateForDataset(requestedDataset);
161     } else { // assume that either the dataset matches or an appropriate failover has been chosen
162       ProductWrapper<E> wrapper = sourceGen.generate(getResultWrapper());
163       return (wrapper != null ? wrapper.unwrap() : null);
164     }
165   }
166 
167   /**
168    * Random dataset string.
169    *
170    * @return the string
171    */
172   public String randomDataset() {
173     if (getSource() instanceof CompositeDatasetGenerator) {
174       Dataset dataset = DatasetUtil.getDataset(nesting, datasetName);
175       return RandomUtil.randomElement(dataset.getSubSets()).getName();
176     } else {
177       return datasetName;
178     }
179   }
180 
181 
182   // helper methods --------------------------------------------------------------------------------------------------
183 
184   /**
185    * Create dataset generator weighted dataset generator.
186    *
187    * @param dataset  the dataset
188    * @param required the required
189    * @param fallback the fallback
190    * @return the weighted dataset generator
191    */
192   protected WeightedDatasetGenerator<E> createDatasetGenerator(Dataset dataset, boolean required, boolean fallback) {
193     WeightedDatasetGenerator<E> generator = null;
194     if (!isAtomic(dataset)) {
195       generator = createCompositeDatasetGenerator(dataset, fallback);
196     }
197     if (isAtomic(dataset) || (generator == null && required)) {
198       generator = createAtomicDatasetGenerator(dataset, required);
199     }
200     if (generator != null) {
201       supportedDatasets.add(dataset.getName());
202     }
203     return generator;
204   }
205 
206   /**
207    * Is atomic boolean.
208    *
209    * @param dataset the dataset
210    * @return the boolean
211    */
212   protected boolean isAtomic(Dataset dataset) {
213     return dataset.isAtomic();
214   }
215 
216   /**
217    * Create composite dataset generator composite dataset generator.
218    *
219    * @param dataset  the dataset
220    * @param fallback the fallback
221    * @return the composite dataset generator
222    */
223   protected CompositeDatasetGenerator<E> createCompositeDatasetGenerator(Dataset dataset, boolean fallback) {
224     CompositeDatasetGenerator<E> generator = new CompositeDatasetGenerator<>(nesting, dataset.getName(), fallback);
225     for (Dataset subSet : dataset.getSubSets()) {
226       WeightedDatasetGenerator<E> subGenerator = createDatasetGenerator(subSet, false, fallback);
227       if (subGenerator != null) {
228         generator.addSubDataset(subGenerator, subGenerator.getWeight());
229       }
230     }
231     if (generator.getSource().getSources().size() > 0) {
232       return generator;
233     } else {
234       return null;
235     }
236   }
237 
238   /**
239    * Create atomic dataset generator atomic dataset generator.
240    *
241    * @param dataset  the dataset
242    * @param required the required
243    * @return the atomic dataset generator
244    */
245   protected AtomicDatasetGenerator<E> createAtomicDatasetGenerator(Dataset dataset, boolean required) {
246     WeightedGenerator<E> generator = createGeneratorForAtomicDataset(dataset);
247     if (generator != null) {
248       totalWeight += generator.getWeight();
249       return new AtomicDatasetGenerator<>(generator, nesting, dataset.getName());
250     }
251     if (required) {
252       throw new InvalidGeneratorSetupException("Unable to create generator for atomic dataset: " + dataset.getName());
253     } else {
254       return null;
255     }
256   }
257 
258   /**
259    * Create generator for atomic dataset weighted generator.
260    *
261    * @param dataset the dataset
262    * @return the weighted generator
263    */
264   protected abstract WeightedGenerator<E> createGeneratorForAtomicDataset(Dataset dataset);
265 
266   @Override
267   public DatasetBasedGenerator<E> getSource() {
268     return (DatasetBasedGenerator<E>) super.getSource();
269   }
270 
271 
272   // java.lang.Object overrides --------------------------------------------------------------------------------------
273 
274   @Override
275   public String toString() {
276     return getClass().getSimpleName() + '[' + nesting + ':' + datasetName + ']';
277   }
278 
279 }