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.StorageSystem;
31  import com.rapiddweller.benerator.composite.BlankEntityGenerator;
32  import com.rapiddweller.benerator.composite.ComponentTypeConverter;
33  import com.rapiddweller.benerator.composite.GeneratorComponent;
34  import com.rapiddweller.benerator.composite.SimpleTypeEntityGenerator;
35  import com.rapiddweller.benerator.composite.SourceAwareGenerator;
36  import com.rapiddweller.benerator.distribution.DistributingGenerator;
37  import com.rapiddweller.benerator.distribution.Distribution;
38  import com.rapiddweller.benerator.engine.BeneratorContext;
39  import com.rapiddweller.benerator.engine.expression.ScriptExpression;
40  import com.rapiddweller.benerator.util.FilteringGenerator;
41  import com.rapiddweller.benerator.wrapper.DataSourceGenerator;
42  import com.rapiddweller.benerator.wrapper.EntityPartSource;
43  import com.rapiddweller.benerator.wrapper.WrapperFactory;
44  import com.rapiddweller.common.ConfigurationError;
45  import com.rapiddweller.common.Converter;
46  import com.rapiddweller.common.StringUtil;
47  import com.rapiddweller.format.DataSource;
48  import com.rapiddweller.format.fixedwidth.FixedWidthColumnDescriptor;
49  import com.rapiddweller.format.fixedwidth.FixedWidthRowTypeDescriptor;
50  import com.rapiddweller.format.fixedwidth.FixedWidthUtil;
51  import com.rapiddweller.format.script.ScriptConverterForStrings;
52  import com.rapiddweller.format.script.ScriptUtil;
53  import com.rapiddweller.format.util.DataFileUtil;
54  import com.rapiddweller.model.data.ComplexTypeDescriptor;
55  import com.rapiddweller.model.data.ComponentDescriptor;
56  import com.rapiddweller.model.data.Entity;
57  import com.rapiddweller.model.data.EntitySource;
58  import com.rapiddweller.model.data.InstanceDescriptor;
59  import com.rapiddweller.model.data.Mode;
60  import com.rapiddweller.model.data.TypeDescriptor;
61  import com.rapiddweller.model.data.Uniqueness;
62  import com.rapiddweller.platform.csv.CSVEntitySourceProvider;
63  import com.rapiddweller.platform.dbunit.DbUnitEntitySource;
64  import com.rapiddweller.platform.fixedwidth.FixedWidthEntitySource;
65  import com.rapiddweller.platform.xls.XLSEntitySourceProvider;
66  import com.rapiddweller.script.BeanSpec;
67  import com.rapiddweller.script.DatabeneScriptParser;
68  import com.rapiddweller.script.Expression;
69  
70  import java.text.ParseException;
71  import java.util.ArrayList;
72  import java.util.List;
73  
74  /**
75   * Creates entity generators from entity metadata.<br/>
76   * <br/>
77   * Created: 08.09.2007 07:45:40
78   *
79   * @author Volker Bergmann
80   */
81  public class ComplexTypeGeneratorFactory extends TypeGeneratorFactory<ComplexTypeDescriptor> {
82  
83    private static final ComplexTypeGeneratorFactoryatorFactory.html#ComplexTypeGeneratorFactory">ComplexTypeGeneratorFactory INSTANCE = new ComplexTypeGeneratorFactory();
84  
85    /**
86     * Gets instance.
87     *
88     * @return the instance
89     */
90    public static ComplexTypeGeneratorFactory getInstance() {
91      return INSTANCE;
92    }
93  
94    /**
95     * Instantiates a new Complex type generator factory.
96     */
97    protected ComplexTypeGeneratorFactory() {
98    }
99  
100   @Override
101   protected Generator<?> applyComponentBuilders(Generator<?> generator, ComplexTypeDescriptor descriptor,
102                                                 String instanceName, Uniqueness uniqueness, BeneratorContext context) {
103     generator = createMutatingEntityGenerator(instanceName, descriptor, uniqueness, context, generator);
104     return super.applyComponentBuilders(generator, descriptor, instanceName, uniqueness, context);
105   }
106 
107   @Override
108   protected Generator<Entity> createSourceGenerator(
109       ComplexTypeDescriptor descriptor, Uniqueness uniqueness, BeneratorContext context) {
110     // if no sourceObject is specified, there's nothing to do
111     String sourceSpec = descriptor.getSource();
112     if (sourceSpec == null) {
113       return null;
114     }
115     Object sourceObject = null;
116     if (ScriptUtil.isScript(sourceSpec)) {
117       Object tmp = ScriptUtil.evaluate(sourceSpec, context); // TODO v0.8 When to resolve scripts?
118       if (tmp instanceof String) {
119         sourceSpec = (String) tmp;
120         sourceObject = context.get(sourceSpec);
121       } else {
122         sourceObject = tmp;
123       }
124     } else if (context.hasProductNameInScope(sourceSpec)) {
125       String partName = StringUtil.lastToken(descriptor.getName(), '.');
126       sourceObject = new EntityPartSource(sourceSpec, partName, context);
127     } else {
128       sourceObject = context.get(sourceSpec);
129     }
130 
131     // create sourceObject generator
132 
133     Generator<Entity> generator = null;
134     if (sourceObject != null) {
135       generator = createSourceGeneratorFromObject(descriptor, context, sourceObject);
136     } else {
137       String segment = descriptor.getSegment();
138       if (DataFileUtil.isXmlDocument(sourceSpec)) {
139         generator = new DataSourceGenerator<>(new DbUnitEntitySource(sourceSpec, context));
140       } else if (DataFileUtil.isCsvDocument(sourceSpec)) {
141         generator = createCSVSourceGenerator(descriptor, context, sourceSpec);
142       } else if (DataFileUtil.isFixedColumnWidthFile(sourceSpec)) {
143         generator = createFixedColumnWidthSourceGenerator(descriptor, context, sourceSpec);
144       } else if (DataFileUtil.isExcelDocument(sourceSpec)) {
145         generator = createXLSSourceGenerator(descriptor, context, sourceSpec, segment);
146       } else {
147         try {
148           BeanSpec sourceBeanSpec = DatabeneScriptParser.resolveBeanSpec(sourceSpec, context);
149           sourceObject = sourceBeanSpec.getBean();
150           generator = createSourceGeneratorFromObject(descriptor, context, sourceObject);
151           if (sourceBeanSpec.isReference() && !(sourceObject instanceof StorageSystem)) {
152             generator = WrapperFactory.preventClosing(generator);
153           }
154         } catch (Exception e) {
155           throw new UnsupportedOperationException("Error resolving source: " + sourceSpec, e);
156         }
157       }
158     }
159     if (generator.getGeneratedType() != Entity.class) {
160       generator = new SimpleTypeEntityGenerator(generator, descriptor);
161     }
162     if (descriptor.getFilter() != null) {
163       Expression<Boolean> filter
164           = new ScriptExpression<>(ScriptUtil.parseScriptText(descriptor.getFilter()));
165       generator = new FilteringGenerator<>(generator, filter);
166     }
167     Distribution distribution = FactoryUtil.getDistribution(descriptor.getDistribution(), uniqueness, false, context);
168     if (distribution != null) {
169       generator = new DistributingGenerator<>(generator, distribution, uniqueness.isUnique());
170     }
171     return generator;
172   }
173 
174   @Override
175   protected Generator<?> createSpecificGenerator(ComplexTypeDescriptor descriptor, String instanceName,
176                                                  boolean nullable, Uniqueness uniqueness, BeneratorContext context) {
177     return null;
178   }
179 
180   @Override
181   protected Generator<?> createHeuristicGenerator(ComplexTypeDescriptor type, String instanceName,
182                                                   Uniqueness uniqueness, BeneratorContext context) {
183     if (DescriptorUtil.isWrappedSimpleType(type)) {
184       return createSimpleTypeEntityGenerator(type, uniqueness, context);
185     } else {
186       return new BlankEntityGenerator(type);
187     }
188   }
189 
190   @Override
191   protected Class<?> getGeneratedType(ComplexTypeDescriptor descriptor) {
192     return Entity.class;
193   }
194 
195   /**
196    * Create mutating entity generator generator.
197    *
198    * @param name            the name
199    * @param descriptor      the descriptor
200    * @param ownerUniqueness the owner uniqueness
201    * @param context         the context
202    * @param source          the source
203    * @return the generator
204    */
205   @SuppressWarnings("unchecked")
206   public static Generator<?> createMutatingEntityGenerator(String name, ComplexTypeDescriptor descriptor,
207                                                            Uniqueness ownerUniqueness, BeneratorContext context, Generator<?> source) {
208     List<GeneratorComponent<Entity>> generatorComponent =
209         createMutatingGeneratorComponents(descriptor, ownerUniqueness, context);
210     return new SourceAwareGenerator<>(name, (Generator<Entity>) source, generatorComponent, context);
211   }
212 
213   // private helpers -------------------------------------------------------------------------------------------------
214 
215   @SuppressWarnings({"unchecked", "rawtypes"})
216   private static Generator<Entity> createSourceGeneratorFromObject(ComplexTypeDescriptor descriptor,
217                                                                    BeneratorContext context, Object sourceObject) {
218     Generator<Entity> generator;
219     if (sourceObject instanceof StorageSystem) {
220       StorageSystem/../com/rapiddweller/benerator/StorageSystem.html#StorageSystem">StorageSystem storage = (StorageSystem) sourceObject;
221       String selector = descriptor.getSelector();
222       String subSelector = descriptor.getSubSelector();
223       if (!StringUtil.isEmpty(subSelector)) {
224         DataSource<Entity> dataSource = storage.queryEntities(descriptor.getName(), subSelector, context);
225         generator = WrapperFactory.applyHeadCycler(new DataSourceGenerator<>(dataSource));
226       } else {
227         generator = new DataSourceGenerator<>(storage.queryEntities(descriptor.getName(), selector, context));
228       }
229     } else if (sourceObject instanceof Generator) {
230       generator = (Generator<Entity>) sourceObject;
231     } else if (sourceObject instanceof EntitySource) {
232       generator = new DataSourceGenerator<>((EntitySource) sourceObject);
233     } else if (sourceObject instanceof DataSource) {
234       DataSource dataSource = (DataSource) sourceObject;
235       if (!Entity.class.isAssignableFrom(dataSource.getType())) {
236         throw new UnsupportedOperationException("Not a supported data type to iterate: " + dataSource.getType());
237       }
238       generator = new DataSourceGenerator<Entity>(dataSource);
239     } else {
240       throw new UnsupportedOperationException("Source type not supported: " + sourceObject.getClass());
241     }
242     return generator;
243   }
244 
245   private static Generator<Entity> createFixedColumnWidthSourceGenerator(
246       ComplexTypeDescriptor descriptor, BeneratorContext context, String sourceName) {
247     Generator<Entity> generator;
248     String encoding = descriptor.getEncoding();
249     if (encoding == null) {
250       encoding = context.getDefaultEncoding();
251     }
252     String pattern = descriptor.getPattern();
253     if (pattern == null) {
254       throw new ConfigurationError("No pattern specified for FCW file import: " + sourceName);
255     }
256     try {
257       FixedWidthRowTypeDescriptor rowDescriptor = FixedWidthUtil.parseBeanColumnsSpec(
258           pattern, descriptor.getName(), null, context.getDefaultLocale());
259       FixedWidthColumnDescriptor[] ffcd = rowDescriptor.getColumnDescriptors();
260       Converter<String, String> scriptConverter = DescriptorUtil.createStringScriptConverter(context);
261       FixedWidthEntitySourcehEntitySource.html#FixedWidthEntitySource">FixedWidthEntitySource iterable = new FixedWidthEntitySource(sourceName, descriptor, scriptConverter, encoding, null, ffcd);
262       iterable.setContext(context);
263       generator = new DataSourceGenerator<>(iterable);
264       return generator;
265     } catch (ParseException e) {
266       throw new ConfigurationError("Error parsing fixed-width pattern: " + pattern, e);
267     }
268   }
269 
270   private static Generator<Entity> createCSVSourceGenerator(
271       ComplexTypeDescriptor complexType, BeneratorContext context, String sourceName) {
272     String encoding = complexType.getEncoding();
273     if (encoding == null) {
274       encoding = context.getDefaultEncoding();
275     }
276     Converter<String, String> scriptConverter = DescriptorUtil.createStringScriptConverter(context);
277     char separator = DescriptorUtil.getSeparator(complexType, context);
278     DataSourceProvider<Entity> fileProvider = new CSVEntitySourceProvider(complexType, scriptConverter,
279         separator, encoding);
280     return createEntitySourceGenerator(complexType, context, sourceName, fileProvider);
281   }
282 
283   private static Generator<Entity> createXLSSourceGenerator(
284       ComplexTypeDescriptor complexType, BeneratorContext context, String sourceName, String segment) {
285     ScriptConverterForStrings converter = new ScriptConverterForStrings(context);
286     boolean formatted = isFormatted(complexType);
287     XLSEntitySourceProviderer.html#XLSEntitySourceProvider">XLSEntitySourceProvider fileProvider = new XLSEntitySourceProvider(complexType, formatted, converter);
288     return createEntitySourceGenerator(complexType, context, sourceName, fileProvider);
289   }
290 
291   private static Generator<Entity> createSimpleTypeEntityGenerator(ComplexTypeDescriptor complexType,
292                                                                    Uniqueness ownerUniqueness, BeneratorContext context) {
293     TypeDescriptor contentType = complexType.getComponent(ComplexTypeDescriptor.__SIMPLE_CONTENT).getTypeDescriptor();
294     Generator<?> generator = MetaGeneratorFactory.createTypeGenerator(
295         contentType, complexType.getName(), false, ownerUniqueness, context);
296     return new SimpleTypeEntityGenerator(generator, complexType);
297   }
298 
299   /**
300    * Create mutating generator components list.
301    *
302    * @param descriptor      the descriptor
303    * @param ownerUniqueness the owner uniqueness
304    * @param context         the context
305    * @return the list
306    */
307   @SuppressWarnings("unchecked")
308   public static List<GeneratorComponent<Entity>> createMutatingGeneratorComponents(ComplexTypeDescriptor descriptor,
309                                                                                    Uniqueness ownerUniqueness, BeneratorContext context) {
310     List<GeneratorComponent<Entity>> generatorComponents = new ArrayList<>();
311     for (InstanceDescriptor part : descriptor.getDeclaredParts()) {
312       if (!(part instanceof ComponentDescriptor) ||
313           part.getMode() != Mode.ignored && !ComplexTypeDescriptor.__SIMPLE_CONTENT.equals(part.getName())) {
314         try {
315           GeneratorComponent<Entity> generatorComponent =
316               (GeneratorComponent<Entity>) GeneratorComponentFactory.createGeneratorComponent(part, ownerUniqueness, context);
317           generatorComponents.add(generatorComponent);
318         } catch (Exception e) {
319           throw new ConfigurationError("Error creating component builder for " + part, e);
320         }
321       }
322     }
323     return generatorComponents;
324   }
325 
326   private static Generator<Entity> createEntitySourceGenerator(ComplexTypeDescriptor complexType,
327                                                                BeneratorContext context, String sourceName, DataSourceProvider<Entity> factory) {
328     Generator<Entity> generator =
329         SourceFactory.createRawSourceGenerator(complexType.getNesting(), complexType.getDataset(), sourceName, factory, Entity.class, context);
330     generator = WrapperFactory.applyConverter(generator, new ComponentTypeConverter(complexType));
331     return generator;
332   }
333 
334 }