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.ArrayElementTypeConverter;
32  import com.rapiddweller.benerator.composite.BlankArrayGenerator;
33  import com.rapiddweller.benerator.distribution.DistributingGenerator;
34  import com.rapiddweller.benerator.distribution.Distribution;
35  import com.rapiddweller.benerator.engine.BeneratorContext;
36  import com.rapiddweller.benerator.engine.expression.ScriptExpression;
37  import com.rapiddweller.benerator.util.FilteringGenerator;
38  import com.rapiddweller.benerator.wrapper.DataSourceGenerator;
39  import com.rapiddweller.benerator.wrapper.WrapperFactory;
40  import com.rapiddweller.common.ConfigurationError;
41  import com.rapiddweller.common.StringUtil;
42  import com.rapiddweller.common.context.ContextAware;
43  import com.rapiddweller.format.script.ScriptConverterForObjects;
44  import com.rapiddweller.format.script.ScriptConverterForStrings;
45  import com.rapiddweller.format.script.ScriptUtil;
46  import com.rapiddweller.format.util.DataFileUtil;
47  import com.rapiddweller.model.data.ArrayElementDescriptor;
48  import com.rapiddweller.model.data.ArrayTypeDescriptor;
49  import com.rapiddweller.model.data.Entity;
50  import com.rapiddweller.model.data.EntitySource;
51  import com.rapiddweller.model.data.Mode;
52  import com.rapiddweller.model.data.Uniqueness;
53  import com.rapiddweller.platform.array.Entity2ArrayConverter;
54  import com.rapiddweller.platform.csv.CSVArraySourceProvider;
55  import com.rapiddweller.platform.xls.XLSArraySourceProvider;
56  import com.rapiddweller.script.BeanSpec;
57  import com.rapiddweller.script.DatabeneScriptParser;
58  import com.rapiddweller.script.Expression;
59  
60  /**
61   * Creates array {@link Generator}s.<br/><br/>
62   * Created: 29.04.2010 07:45:18
63   *
64   * @author Volker Bergmann
65   * @since 0.6.1
66   */
67  public class ArrayTypeGeneratorFactory extends TypeGeneratorFactory<ArrayTypeDescriptor> {
68  
69    @Override
70    protected Generator<Object[]> createSourceGenerator(
71        ArrayTypeDescriptor descriptor, Uniqueness uniqueness, BeneratorContext context) {
72      // if no sourceObject is specified, there's nothing to do
73      String sourceName = descriptor.getSource();
74      if (sourceName == null) {
75        return null;
76      }
77      // create sourceObject generator
78      Generator<Object[]> generator = null;
79      Object contextSourceObject = context.get(sourceName);
80      if (contextSourceObject != null) {
81        generator = createSourceGeneratorFromObject(descriptor, context, contextSourceObject);
82      } else {
83        if (DataFileUtil.isCsvDocument(sourceName)) {
84          generator = createCSVSourceGenerator(descriptor, context, sourceName);
85        } else if (DataFileUtil.isExcelDocument(sourceName)) {
86          generator = createXLSSourceGenerator(descriptor, context, sourceName);
87        } else {
88          try {
89            BeanSpec sourceBeanSpec = DatabeneScriptParser.resolveBeanSpec(sourceName, context);
90            Object sourceObject = sourceBeanSpec.getBean();
91            if (!sourceBeanSpec.isReference() && sourceObject instanceof ContextAware) {
92              ((ContextAware) sourceObject).setContext(context);
93            }
94            generator = createSourceGeneratorFromObject(descriptor, context, sourceObject);
95            if (sourceBeanSpec.isReference()) {
96              generator = WrapperFactory.preventClosing(generator);
97            }
98            return generator;
99          } catch (Exception e) {
100           throw new UnsupportedOperationException("Unknown source type: " + sourceName);
101         }
102       }
103     }
104     if (descriptor.getFilter() != null) {
105       Expression<Boolean> filter
106           = new ScriptExpression<>(ScriptUtil.parseScriptText(descriptor.getFilter()));
107       generator = new FilteringGenerator<>(generator, filter);
108     }
109     Distribution distribution = FactoryUtil.getDistribution(descriptor.getDistribution(), uniqueness, false, context);
110     if (distribution != null) {
111       generator = new DistributingGenerator<>(generator, distribution, uniqueness.isUnique());
112     }
113     return generator;
114   }
115 
116   @Override
117   protected Generator<?> createSpecificGenerator(ArrayTypeDescriptor descriptor, String instanceName,
118                                                  boolean nullable, Uniqueness uniqueness, BeneratorContext context) {
119     return null;
120   }
121 
122   @Override
123   protected Generator<?> createHeuristicGenerator(
124       ArrayTypeDescriptor descriptor, String instanceName,
125       Uniqueness uniqueness, BeneratorContext context) {
126     return new BlankArrayGenerator(descriptor.getElementCount());
127   }
128 
129   @SuppressWarnings({"rawtypes", "unchecked"})
130   @Override
131   protected Generator<?> applyComponentBuilders(Generator<?> generator, ArrayTypeDescriptor descriptor, String instanceName,
132                                                 Uniqueness uniqueness, BeneratorContext context) {
133     Generator[] generators;
134     // create synthetic element generators if necessary
135     if (generator instanceof BlankArrayGenerator) {
136       generators = createSyntheticElementGenerators(descriptor, uniqueness, context);
137       generator = context.getGeneratorFactory().createCompositeArrayGenerator(
138           Object.class, generators, uniqueness);
139     }
140     // ... and don't forget to support the parent class' functionality
141     generator = super.applyComponentBuilders(generator, descriptor, instanceName, uniqueness, context);
142     return generator;
143   }
144 
145   @Override
146   protected Class<?> getGeneratedType(ArrayTypeDescriptor descriptor) {
147     return Object[].class;
148   }
149 
150   // private helpers -------------------------------------------------------------------------------------------------
151 
152   private Generator<Object[]> createCSVSourceGenerator(ArrayTypeDescriptor arrayType, BeneratorContext context,
153                                                        String sourceName) {
154     logger.debug("createCSVSourceGenerator({})", arrayType);
155     String encoding = arrayType.getEncoding();
156     if (encoding == null) {
157       encoding = context.getDefaultEncoding();
158     }
159     char separator = DescriptorUtil.getSeparator(arrayType, context);
160     boolean rowBased = (arrayType.isRowBased() != null ? arrayType.isRowBased() : true);
161     DataSourceProvider<Object[]> factory =
162         new CSVArraySourceProvider(arrayType.getName(), new ScriptConverterForStrings(context), rowBased, separator, encoding);
163     Generator<Object[]> generator =
164         SourceFactory.createRawSourceGenerator(arrayType.getNesting(), arrayType.getDataset(), sourceName, factory, Object[].class, context);
165     return WrapperFactory.applyConverter(generator, new ArrayElementTypeConverter(arrayType));
166   }
167 
168   private Generator<Object[]> createXLSSourceGenerator(
169       ArrayTypeDescriptor arrayType, BeneratorContext context, String sourceName) {
170     logger.debug("createXLSSourceGenerator({})", arrayType);
171     boolean rowBased = (arrayType.isRowBased() != null ? arrayType.isRowBased() : true);
172     String emptyMarker = arrayType.getEmptyMarker();
173     String nullMarker = arrayType.getNullMarker();
174     boolean formatted = isFormatted(arrayType);
175     DataSourceProvider<Object[]> factory = new XLSArraySourceProvider(formatted,
176         new ScriptConverterForObjects(context), emptyMarker, nullMarker, rowBased);
177     Generator<Object[]> generator =
178         SourceFactory.createRawSourceGenerator(arrayType.getNesting(), arrayType.getDataset(), sourceName, factory, Object[].class, context);
179     generator = WrapperFactory.applyConverter(generator, new ArrayElementTypeConverter(arrayType));
180     return generator;
181   }
182 
183   @SuppressWarnings({"unchecked", "rawtypes"})
184   private static Generator<Object[]> createSourceGeneratorFromObject(ArrayTypeDescriptor descriptor,
185                                                                      BeneratorContext context, Object sourceObject) {
186     Generator<Object[]> generator;
187     if (sourceObject instanceof StorageSystem) {
188       StorageSystem/../com/rapiddweller/benerator/StorageSystem.html#StorageSystem">StorageSystem storage = (StorageSystem) sourceObject;
189       String selector = descriptor.getSelector();
190       String subSelector = descriptor.getSubSelector();
191       if (!StringUtil.isEmpty(subSelector)) {
192         generator = WrapperFactory.applyHeadCycler(new DataSourceGenerator(storage.query(subSelector, false, context)));
193       } else {
194         generator = new DataSourceGenerator(storage.query(selector, false, context));
195       }
196     } else if (sourceObject instanceof EntitySource) {
197       DataSourceGenerator<Entity> entityGenerator = new DataSourceGenerator<>((EntitySource) sourceObject);
198       generator = WrapperFactory.applyConverter(entityGenerator, new Entity2ArrayConverter());
199     } else if (sourceObject instanceof Generator) {
200       generator = (Generator<Object[]>) sourceObject;
201     } else {
202       throw new ConfigurationError("Source type not supported: " + sourceObject.getClass());
203     }
204     return generator;
205   }
206 
207   @SuppressWarnings("rawtypes")
208   private Generator<?>[] createSyntheticElementGenerators(
209       ArrayTypeDescriptor arrayType, Uniqueness uniqueness, BeneratorContext context) {
210     Generatortor.html#Generator">Generator[] result = new Generator[arrayType.getElementCount()];
211     for (int i = 0; i < arrayType.getElementCount(); i++) {
212       ArrayElementDescriptor element = getElementOfTypeOrParents(arrayType, i);
213       if (element.getMode() != Mode.ignored) {
214         Generator<?> generator = InstanceGeneratorFactory.createSingleInstanceGenerator(
215             element, uniqueness, context);
216         result[i] = generator;
217       }
218     }
219     return result;
220   }
221 
222   /**
223    * Gets element of type or parents.
224    *
225    * @param arrayType the array type
226    * @param index     the index
227    * @return the element of type or parents
228    */
229   protected ArrayElementDescriptor getElementOfTypeOrParents(ArrayTypeDescriptor arrayType, int index) {
230     ArrayTypeDescriptor tmp = arrayType;
231     ArrayElementDescriptor result;
232     while ((result = tmp.getElement(index)) == null && tmp.getParent() != null) {
233       tmp = tmp.getParent();
234     }
235     return result;
236   }
237 
238 }