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.engine;
28  
29  import com.rapiddweller.benerator.BeneratorFactory;
30  import com.rapiddweller.benerator.engine.parser.String2DistributionConverter;
31  import com.rapiddweller.benerator.factory.DefaultsProvider;
32  import com.rapiddweller.benerator.factory.GeneratorFactory;
33  import com.rapiddweller.benerator.factory.StochasticGeneratorFactory;
34  import com.rapiddweller.benerator.script.BeneratorScriptFactory;
35  import com.rapiddweller.benerator.script.graaljs.GraalJsScriptFactory;
36  import com.rapiddweller.benerator.script.graalpy.GraalPyScriptFactory;
37  import com.rapiddweller.benerator.wrapper.ProductWrapper;
38  import com.rapiddweller.common.BeanUtil;
39  import com.rapiddweller.common.ConfigurationError;
40  import com.rapiddweller.common.Context;
41  import com.rapiddweller.common.ErrorHandler;
42  import com.rapiddweller.common.IOUtil;
43  import com.rapiddweller.common.Level;
44  import com.rapiddweller.common.LocaleUtil;
45  import com.rapiddweller.common.NullSafeComparator;
46  import com.rapiddweller.common.SystemInfo;
47  import com.rapiddweller.common.bean.ClassCache;
48  import com.rapiddweller.common.context.ContextStack;
49  import com.rapiddweller.common.context.DefaultContext;
50  import com.rapiddweller.common.context.SimpleContextStack;
51  import com.rapiddweller.common.converter.ConverterManager;
52  import com.rapiddweller.common.file.FileSuffixFilter;
53  import com.rapiddweller.domain.address.Country;
54  import com.rapiddweller.format.script.ScriptUtil;
55  import com.rapiddweller.model.data.ComplexTypeDescriptor;
56  import com.rapiddweller.model.data.ComponentDescriptor;
57  import com.rapiddweller.model.data.DataModel;
58  import com.rapiddweller.model.data.DefaultDescriptorProvider;
59  import com.rapiddweller.model.data.DescriptorProvider;
60  import com.rapiddweller.model.data.TypeDescriptor;
61  
62  import java.io.File;
63  import java.util.Locale;
64  import java.util.Map.Entry;
65  import java.util.Objects;
66  import java.util.Set;
67  import java.util.concurrent.ExecutorService;
68  import java.util.concurrent.Executors;
69  
70  /**
71   * Default implementation of {@link BeneratorContext}.<br/><br/>
72   * Created: 02.09.2011 14:36:58
73   *
74   * @author Volker Bergmann
75   * @since 0.7.0
76   */
77  public class DefaultBeneratorContext implements BeneratorContext {
78  
79    // constants -------------------------------------------------------------------------------------------------------
80  
81    /**
82     * The constant CELL_SEPARATOR_SYSPROP.
83     */
84    public static final String CELL_SEPARATOR_SYSPROP = "cell.separator";
85    /**
86     * The constant DEFAULT_CELL_SEPARATOR.
87     */
88    public static final char DEFAULT_CELL_SEPARATOR = ',';
89  
90  
91    // attributes -------------------------------------------------------------------------------------------------------
92  
93    private GeneratorFactory generatorFactory;
94    private final DefaultContext settings;
95    private final ClassCache classCache;
96    private final ContextStack contextStack;
97  
98    /**
99     * The Default encoding.
100    */
101   protected String defaultEncoding = SystemInfo.getFileEncoding();
102   /**
103    * The Default dataset.
104    */
105   protected String defaultDataset = LocaleUtil.getDefaultCountryCode();
106   /**
107    * The Default page size.
108    */
109   protected long defaultPageSize = 1;
110   /**
111    * The Default null.
112    */
113   protected boolean defaultNull = true;
114   /**
115    * The Context uri.
116    */
117   protected String contextUri = "./";
118   /**
119    * The Max count.
120    */
121   public Long maxCount = null;
122   /**
123    * The Default one to one.
124    */
125   public boolean defaultOneToOne = false;
126   /**
127    * The Default imports.
128    */
129   public boolean defaultImports = true;
130   /**
131    * The Accept unknown simple types.
132    */
133   public boolean acceptUnknownSimpleTypes = false;
134 
135 
136   /**
137    * The Default component.
138    */
139   protected ComplexTypeDescriptor defaultComponent;
140   /**
141    * The Executor service.
142    */
143   protected ExecutorService executorService;
144 
145   private ProductWrapper<?> currentProduct;
146 
147   private DataModel dataModel;
148   private final DefaultDescriptorProvider localDescriptorProvider;
149 
150   /**
151    * The Current product name.
152    */
153   protected String currentProductName;
154 
155 
156   // construction ----------------------------------------------------------------------------------------------------
157 
158   static {
159     ScriptUtil.addFactory("js", new GraalJsScriptFactory());
160     ScriptUtil.addFactory("py", new GraalPyScriptFactory());
161     ScriptUtil.addFactory("ben", new BeneratorScriptFactory());
162     ScriptUtil.setDefaultScriptEngine("ben");
163     ConverterManager.getInstance().registerConverterClass(String2DistributionConverter.class); // TODO is this required any longer?
164   }
165 
166   /**
167    * Instantiates a new Default benerator context.
168    */
169   public DefaultBeneratorContext() {
170     this(".");
171   }
172 
173   /**
174    * Instantiates a new Default benerator context.
175    *
176    * @param contextUri the context uri
177    */
178   public DefaultBeneratorContext(String contextUri) {
179     if (contextUri == null) {
180       throw new ConfigurationError("No context URI specified");
181     }
182     this.contextUri = contextUri;
183     this.executorService = createExecutorService();
184     this.dataModel = new DataModel();
185     this.localDescriptorProvider = new DefaultDescriptorProvider("ctx", dataModel);
186     this.defaultComponent = new ComplexTypeDescriptor("benerator:defaultComponent", localDescriptorProvider);
187     this.generatorFactory = new StochasticGeneratorFactory();
188     settings = new DefaultContext();
189     this.contextStack = createContextStack(
190         new DefaultContext(java.lang.System.getenv()),
191         new DefaultContext(java.lang.System.getProperties()),
192         settings,
193         BeneratorFactory.getInstance().createGenerationContext()
194     );
195     set("context", this);
196     if (IOUtil.isFileUri(contextUri)) {
197       addLibFolderToClassLoader();
198     }
199     classCache = new ClassCache();
200   }
201 
202 
203   // properties ------------------------------------------------------------------------------------------------------
204 
205   @Override
206   public GeneratorFactory getGeneratorFactory() {
207     return generatorFactory;
208   }
209 
210   @Override
211   public void setGeneratorFactory(GeneratorFactory generatorFactory) {
212     this.generatorFactory = generatorFactory;
213   }
214 
215   @Override
216   public DescriptorProvider getLocalDescriptorProvider() {
217     return localDescriptorProvider;
218   }
219 
220   @Override
221   public void setDefaultsProvider(DefaultsProvider defaultsProvider) {
222     this.generatorFactory.setDefaultsProvider(defaultsProvider);
223   }
224 
225   @Override
226   public String getDefaultEncoding() {
227     return defaultEncoding;
228   }
229 
230   @Override
231   public void setDefaultEncoding(String defaultEncoding) {
232     SystemInfo.setFileEncoding(defaultEncoding);
233     this.defaultEncoding = defaultEncoding;
234   }
235 
236   @Override
237   public String getDefaultLineSeparator() {
238     return SystemInfo.getLineSeparator();
239   }
240 
241   @Override
242   public void setDefaultLineSeparator(String defaultLineSeparator) {
243     SystemInfo.setLineSeparator(defaultLineSeparator);
244   }
245 
246   @Override
247   public Locale getDefaultLocale() {
248     return Locale.getDefault();
249   }
250 
251   @Override
252   public void setDefaultLocale(Locale defaultLocale) {
253     Locale.setDefault(defaultLocale);
254   }
255 
256   @Override
257   public String getDefaultDataset() {
258     return defaultDataset;
259   }
260 
261   @Override
262   public void setDefaultDataset(String defaultDataset) {
263     this.defaultDataset = defaultDataset;
264     Country country = Country.getInstance(defaultDataset, false);
265     if (country != null) {
266       Country.setDefault(country);
267     }
268   }
269 
270   @Override
271   public long getDefaultPageSize() {
272     return defaultPageSize;
273   }
274 
275   @Override
276   public void setDefaultPageSize(long defaultPageSize) {
277     this.defaultPageSize = defaultPageSize;
278   }
279 
280   @Override
281   public String getDefaultScript() {
282     return ScriptUtil.getDefaultScriptEngine();
283   }
284 
285   @Override
286   public void setDefaultScript(String defaultScript) {
287     ScriptUtil.setDefaultScriptEngine(defaultScript);
288   }
289 
290   @Override
291   public boolean isDefaultNull() {
292     return defaultNull;
293   }
294 
295   @Override
296   public void setDefaultNull(boolean defaultNull) {
297     this.defaultNull = defaultNull;
298   }
299 
300   @Override
301   public char getDefaultSeparator() {
302     return getDefaultCellSeparator();
303   }
304 
305   @Override
306   public void setDefaultSeparator(char defaultSeparator) {
307     System.setProperty(CELL_SEPARATOR_SYSPROP, String.valueOf(defaultSeparator));
308   }
309 
310   @Override
311   public ComponentDescriptor getDefaultComponentConfig(String name) {
312     return defaultComponent.getComponent(name);
313   }
314 
315   @Override
316   public void setDefaultComponentConfig(ComponentDescriptor component) {
317     defaultComponent.addComponent(component);
318   }
319 
320   @Override
321   public String getDefaultErrorHandler() {
322     return ErrorHandler.getDefaultLevel().name();
323   }
324 
325   @Override
326   public void setDefaultErrorHandler(String defaultErrorHandler) {
327     ErrorHandler.setDefaultLevel(Level.valueOf(defaultErrorHandler));
328   }
329 
330   @Override
331   public String getContextUri() {
332     return contextUri;
333   }
334 
335   @Override
336   public void setContextUri(String contextUri) {
337     this.contextUri = contextUri;
338   }
339 
340   @Override
341   public boolean isValidate() {
342     return BeneratorOpts.isValidating();
343   }
344 
345   @Override
346   public void setValidate(boolean validate) {
347     BeneratorOpts.setValidating(validate);
348   }
349 
350   @Override
351   public Long getMaxCount() {
352     return maxCount;
353   }
354 
355   @Override
356   public void setMaxCount(Long maxCount) {
357     this.maxCount = maxCount;
358   }
359 
360   @Override
361   public ExecutorService getExecutorService() {
362     return executorService;
363   }
364 
365   @Override
366   public boolean isDefaultOneToOne() {
367     return defaultOneToOne;
368   }
369 
370   @Override
371   public void setDefaultOneToOne(boolean defaultOneToOne) {
372     this.defaultOneToOne = defaultOneToOne;
373   }
374 
375   @Override
376   public boolean isAcceptUnknownSimpleTypes() {
377     return acceptUnknownSimpleTypes;
378   }
379 
380   @Override
381   public void setAcceptUnknownSimpleTypes(boolean acceptUnknownSimpleTypes) {
382     this.acceptUnknownSimpleTypes = acceptUnknownSimpleTypes;
383     dataModel.setAcceptUnknownPrimitives(acceptUnknownSimpleTypes);
384   }
385 
386   /**
387    * Gets default cell separator.
388    *
389    * @return the default cell separator
390    */
391   public static char getDefaultCellSeparator() {
392     String tmp = System.getProperty(CELL_SEPARATOR_SYSPROP);
393     if (tmp == null) {
394       return DEFAULT_CELL_SEPARATOR;
395     }
396     if (tmp.length() != 1) {
397       throw new ConfigurationError("Cell separator has illegal length: '" + tmp + "'");
398     }
399     return tmp.charAt(0);
400   }
401 
402   @Override
403   public DefaultsProvider getDefaultsProvider() {
404     return getGeneratorFactory().getDefaultsProvider();
405   }
406 
407   @Override
408   public void setDefaultImports(boolean defaultImports) {
409     this.defaultImports = defaultImports;
410   }
411 
412   @Override
413   public boolean isDefaultImports() {
414     return defaultImports;
415   }
416 
417   @Override
418   public ProductWrapper<?> getCurrentProduct() {
419     return currentProduct;
420   }
421 
422   @Override
423   public void setCurrentProduct(ProductWrapper<?> currentProduct) {
424     this.currentProduct = currentProduct;
425   }
426 
427   @Override
428   public DataModel getDataModel() {
429     return dataModel;
430   }
431 
432   @Override
433   public void setDataModel(DataModel dataModel) {
434     this.dataModel = dataModel;
435   }
436 
437 
438   // Context interface -----------------------------------------------------------------------------------------------
439 
440   @Override
441   public Object get(String key) {
442     if (contextStack.contains(key)) {
443       return contextStack.get(key);
444     } else if (key.equalsIgnoreCase(currentProductName) || "this".equalsIgnoreCase(key)) {
445       return currentProduct.unwrap();
446     } else {
447       return null;
448     }
449   }
450 
451   @Override
452   public void set(String key, Object value) {
453     contextStack.set(key, value);
454   }
455 
456   @Override
457   public void remove(String key) {
458     contextStack.remove(key);
459   }
460 
461   @Override
462   public Set<String> keySet() {
463     return contextStack.keySet();
464   }
465 
466   @Override
467   public Set<Entry<String, Object>> entrySet() {
468     return contextStack.entrySet();
469   }
470 
471   @Override
472   public boolean contains(String key) {
473     return (key != null && (key.equalsIgnoreCase(currentProductName) || "this".equalsIgnoreCase(key) || contextStack.contains(key)));
474   }
475 
476 
477   // class-loading interface -----------------------------------------------------------------------------------------
478 
479   @Override
480   public Class<?> forName(String className) {
481     return classCache.forName(className);
482   }
483 
484   @Override
485   public void importClass(String className) {
486     classCache.importClass(className);
487   }
488 
489   @Override
490   public void importPackage(String packageName) {
491     classCache.importPackage(packageName);
492   }
493 
494   @Override
495   public void importDefaults() {
496     // import frequently used Benerator packages
497     importPackage("com.rapiddweller.benerator.consumer");
498     importPackage("com.rapiddweller.benerator.primitive");
499     importPackage("com.rapiddweller.benerator.primitive.datetime");
500     importPackage("com.rapiddweller.benerator.distribution.sequence");
501     importPackage("com.rapiddweller.benerator.distribution.function");
502     importPackage("com.rapiddweller.benerator.distribution.cumulative");
503     importPackage("com.rapiddweller.benerator.sample");
504     // import ConsoleExporter and LoggingConsumer
505     importPackage("com.rapiddweller.model.consumer");
506     // import format, converters and validators from common
507     importPackage("com.rapiddweller.common.converter");
508     importPackage("com.rapiddweller.common.format");
509     importPackage("com.rapiddweller.common.validator");
510     // import standard platforms
511     importPackage("com.rapiddweller.platform.fixedwidth");
512     importPackage("com.rapiddweller.platform.csv");
513     importPackage("com.rapiddweller.platform.dbunit");
514     importPackage("com.rapiddweller.platform.xls");
515     importPackage("com.rapiddweller.platform.template");
516   }
517 
518 
519   // other interface methods -----------------------------------------------------------------------------------------
520 
521   @Override
522   public void setGlobal(String name, Object value) {
523     settings.set(name, value);
524   }
525 
526   @Override
527   public Object getGlobal(String name) {
528     return settings.get(name);
529   }
530 
531   @Override
532   public void close() {
533     executorService.shutdownNow();
534   }
535 
536   @Override
537   public void addLocalType(TypeDescriptor type) {
538     localDescriptorProvider.addTypeDescriptor(type);
539   }
540 
541   @Override
542   public BeneratorContext createSubContext(String productName) {
543     return new DefaultBeneratorSubContext(productName, this);
544   }
545 
546   /**
547    * Sets current product.
548    *
549    * @param currentProduct     the current product
550    * @param currentProductName the current product name
551    */
552   public void setCurrentProduct(ProductWrapper<?> currentProduct, String currentProductName) {
553     this.currentProductName = currentProductName;
554     setCurrentProduct(currentProduct);
555   }
556 
557   @Override
558   public boolean hasProductNameInScope(String productName) {
559     return (NullSafeComparator.equals(this.currentProductName, productName));
560   }
561 
562   @Override
563   public String resolveRelativeUri(String relativeUri) {
564     return IOUtil.resolveRelativeUri(relativeUri, contextUri);
565   }
566 
567 
568   // non-public helper methods ---------------------------------------------------------------------------------------
569 
570   private void addLibFolderToClassLoader() {
571     File libFolder = new File(contextUri, "lib");
572     if (libFolder.exists()) {
573       Thread.currentThread().setContextClassLoader(BeanUtil.createDirectoryClassLoader(libFolder));
574       for (File jarFile : Objects.requireNonNull(libFolder.listFiles(new FileSuffixFilter("jar", false)))) {
575         ClassLoader classLoader = BeanUtil.createJarClassLoader(jarFile);
576         Thread.currentThread().setContextClassLoader(classLoader);
577       }
578     }
579   }
580 
581   /**
582    * Create executor service executor service.
583    *
584    * @return the executor service
585    */
586   protected ExecutorService createExecutorService() {
587     return Executors.newSingleThreadExecutor();
588   }
589 
590   /**
591    * Create context stack context stack.
592    *
593    * @param contexts the contexts
594    * @return the context stack
595    */
596   protected ContextStack createContextStack(Context... contexts) {
597     return new SimpleContextStack(contexts);
598   }
599 
600 
601   // java.lang.Object overrides --------------------------------------------------------------------------------------
602 
603   @Override
604   public String toString() {
605     return getClass() + "[" + currentProductName + "]";
606   }
607 
608 }