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.BeneratorFactory;
30  import com.rapiddweller.benerator.Generator;
31  import com.rapiddweller.benerator.distribution.Distribution;
32  import com.rapiddweller.benerator.engine.BeneratorContext;
33  import com.rapiddweller.benerator.parser.ModelParser;
34  import com.rapiddweller.benerator.primitive.DynamicCountGenerator;
35  import com.rapiddweller.benerator.sample.ConstantGenerator;
36  import com.rapiddweller.benerator.util.ExpressionBasedGenerator;
37  import com.rapiddweller.benerator.wrapper.WrapperFactory;
38  import com.rapiddweller.common.BeanUtil;
39  import com.rapiddweller.common.ConfigurationError;
40  import com.rapiddweller.common.Context;
41  import com.rapiddweller.common.ConversionException;
42  import com.rapiddweller.common.Converter;
43  import com.rapiddweller.common.NullSafeComparator;
44  import com.rapiddweller.common.ParseException;
45  import com.rapiddweller.common.StringUtil;
46  import com.rapiddweller.common.TimeUtil;
47  import com.rapiddweller.common.Validator;
48  import com.rapiddweller.common.converter.AnyConverter;
49  import com.rapiddweller.common.converter.ConverterChain;
50  import com.rapiddweller.common.converter.FormatFormatConverter;
51  import com.rapiddweller.common.converter.String2NumberConverter;
52  import com.rapiddweller.common.converter.ToStringConverter;
53  import com.rapiddweller.common.validator.AndValidator;
54  import com.rapiddweller.common.validator.bean.BeanConstraintValidator;
55  import com.rapiddweller.common.xml.XMLUtil;
56  import com.rapiddweller.format.script.ScriptConverterForStrings;
57  import com.rapiddweller.model.data.ArrayTypeDescriptor;
58  import com.rapiddweller.model.data.ComplexTypeDescriptor;
59  import com.rapiddweller.model.data.ComponentDescriptor;
60  import com.rapiddweller.model.data.IdDescriptor;
61  import com.rapiddweller.model.data.InstanceDescriptor;
62  import com.rapiddweller.model.data.SimpleTypeDescriptor;
63  import com.rapiddweller.model.data.TypeDescriptor;
64  import com.rapiddweller.model.data.Uniqueness;
65  import com.rapiddweller.model.data.VariableHolder;
66  import com.rapiddweller.script.BeanSpec;
67  import com.rapiddweller.script.DatabeneScriptParser;
68  import com.rapiddweller.script.Expression;
69  import com.rapiddweller.script.PrimitiveType;
70  import com.rapiddweller.script.expression.ConstantExpression;
71  import com.rapiddweller.script.expression.ExpressionUtil;
72  import com.rapiddweller.script.expression.MinExpression;
73  import org.w3c.dom.Element;
74  
75  import javax.validation.ConstraintValidator;
76  import java.text.DateFormat;
77  import java.text.SimpleDateFormat;
78  import java.util.List;
79  
80  import static com.rapiddweller.benerator.engine.DescriptorConstants.COMPONENT_TYPES;
81  import static com.rapiddweller.benerator.engine.DescriptorConstants.EL_VALUE;
82  import static com.rapiddweller.benerator.engine.DescriptorConstants.EL_VARIABLE;
83  import static com.rapiddweller.model.data.SimpleTypeDescriptor.MAX_LENGTH;
84  import static com.rapiddweller.model.data.SimpleTypeDescriptor.PATTERN;
85  
86  /**
87   * Utility class for parsing and combining descriptor settings.<br/>
88   * <br/>
89   * Created at 31.12.2008 09:28:28
90   *
91   * @author Volker Bergmann
92   * @since 0.5.7
93   */
94  public class DescriptorUtil {
95  
96    private DescriptorUtil() {
97    }
98  
99    /**
100    * Convert type object.
101    *
102    * @param sourceValue the source value
103    * @param targetType  the target type
104    * @return the object
105    */
106   public static Object convertType(Object sourceValue, SimpleTypeDescriptor targetType) {
107     if (sourceValue == null) {
108       return null;
109     }
110     PrimitiveType primitive = targetType.getPrimitiveType();
111     if (primitive == null) {
112       primitive = PrimitiveType.STRING;
113     }
114     Class<?> javaType = primitive.getJavaType();
115     return AnyConverter.convert(sourceValue, javaType);
116   }
117 
118   /**
119    * Is wrapped simple type boolean.
120    *
121    * @param complexType the complex type
122    * @return the boolean
123    */
124   public static boolean isWrappedSimpleType(ComplexTypeDescriptor complexType) {
125     List<ComponentDescriptor> components = complexType.getComponents();
126     return (components.size() == 1
127         && ComplexTypeDescriptor.__SIMPLE_CONTENT.equals(components.get(0).getName()));
128   }
129 
130   /**
131    * Create converting generator generator.
132    *
133    * @param descriptor the descriptor
134    * @param generator  the generator
135    * @param context    the context
136    * @return the generator
137    */
138   @SuppressWarnings({"unchecked", "rawtypes"})
139   public static Generator<?> createConvertingGenerator(TypeDescriptor descriptor,
140                                                        Generator<?> generator, BeneratorContext context) {
141     Converter<?, ?> converter = DescriptorUtil.getConverter(descriptor.getConverter(), context);
142     if (converter != null) {
143       if (descriptor.getPattern() != null && BeanUtil.hasProperty(converter.getClass(), PATTERN)) {
144         BeanUtil.setPropertyValue(converter, PATTERN, descriptor.getPattern(), false);
145       }
146       return WrapperFactory.applyConverter((Generator) generator, converter);
147     }
148     return generator;
149   }
150 
151   /**
152    * Gets generator by name.
153    *
154    * @param descriptor the descriptor
155    * @param context    the context
156    * @return the generator by name
157    */
158   public static Generator<?> getGeneratorByName(TypeDescriptor descriptor, BeneratorContext context) {
159     try {
160       Generator<?> generator = null;
161       String generatorSpec = descriptor.getGenerator();
162       if (generatorSpec != null) {
163         if (generatorSpec.startsWith("{") && generatorSpec.endsWith("}")) {
164           generatorSpec = generatorSpec.substring(1, generatorSpec.length() - 1);
165         }
166         BeanSpec generatorBeanSpec = DatabeneScriptParser.resolveBeanSpec(generatorSpec, context);
167         generator = (Generator<?>) generatorBeanSpec.getBean();
168         FactoryUtil.mapDetailsToBeanProperties(descriptor, generator, context);
169         if (generatorBeanSpec.isReference()) {
170           generator = WrapperFactory.preventClosing(generator);
171         }
172       }
173       return generator;
174     } catch (ParseException e) {
175       throw new ConfigurationError("Error in generator spec", e);
176     }
177   }
178 
179   /**
180    * Gets validator.
181    *
182    * @param validatorSpec the validator spec
183    * @param context       the context
184    * @return the validator
185    */
186   @SuppressWarnings({"unchecked", "rawtypes"})
187   public static Validator getValidator(String validatorSpec, BeneratorContext context) {
188     try {
189       if (StringUtil.isEmpty(validatorSpec)) {
190         return null;
191       }
192 
193       Validator result = null;
194       Expression[] beanExpressions = DatabeneScriptParser.parseBeanSpecList(validatorSpec);
195       Object[] beans = ExpressionUtil.evaluateAll(beanExpressions, context);
196       for (Object bean : beans) {
197         // check validator type
198         Validator validator;
199         if (bean instanceof Validator) {
200           validator = (Validator<?>) bean;
201         } else if (bean instanceof ConstraintValidator) {
202           validator = new BeanConstraintValidator((ConstraintValidator) bean);
203         } else {
204           throw new ConfigurationError("Unknown validator type: " + BeanUtil.simpleClassName(bean));
205         }
206 
207         // compose one or more validators
208         if (result == null) {
209           // if it is the first or even only validator, simply use it
210           result = validator;
211         } else if (result instanceof AndValidator) {
212           // else compose all validators to an AndValidator
213           ((AndValidator) result).add(validator);
214         } else {
215           result = new AndValidator(result, validator);
216         }
217       }
218       result = BeneratorFactory.getInstance().configureValidator(result, context);
219       return result;
220     } catch (ParseException e) {
221       throw new ConfigurationError("Invalid validator definition", e);
222     }
223   }
224 
225   /**
226    * Gets converter.
227    *
228    * @param converterSpec the converter spec
229    * @param context       the context
230    * @return the converter
231    */
232   @SuppressWarnings({"unchecked", "rawtypes"})
233   public static Converter getConverter(String converterSpec, BeneratorContext context) {
234     try {
235       if (StringUtil.isEmpty(converterSpec)) {
236         return null;
237       }
238 
239       Converter result = null;
240       Expression[] beanExpressions = DatabeneScriptParser.parseBeanSpecList(converterSpec);
241       Object[] beans = ExpressionUtil.evaluateAll(beanExpressions, context);
242       for (Object bean : beans) {
243         Converter converter;
244         if (bean instanceof java.text.Format) {
245           converter = new FormatFormatConverter(Object.class, (java.text.Format) bean, false);
246         } else if (bean instanceof Converter) {
247           converter = (Converter) bean;
248         } else {
249           throw new ConfigurationError(bean + " is not an instance of " + Converter.class);
250         }
251         converter = BeneratorFactory.getInstance().configureConverter(converter, context);
252 
253         if (result == null) {
254           result = converter;
255         } else if (result instanceof ConverterChain) {
256           ((ConverterChain) result).addComponent(converter);
257         } else {
258           result = new ConverterChain(result, converter);
259         }
260       }
261       return result;
262     } catch (ParseException e) {
263       throw new ConfigurationError("Error parsing converter spec: " + converterSpec, e);
264     }
265   }
266 
267   /**
268    * Gets pattern as date format.
269    *
270    * @param descriptor the descriptor
271    * @return the pattern as date format
272    */
273   public static DateFormat getPatternAsDateFormat(TypeDescriptor descriptor) {
274     String pattern = descriptor.getPattern();
275     if (pattern != null) {
276       return new SimpleDateFormat(pattern);
277     } else {
278       return TimeUtil.createDefaultDateFormat();
279     }
280   }
281 
282   /**
283    * Gets uniqueness.
284    *
285    * @param descriptor the descriptor
286    * @param context    the context
287    * @return the uniqueness
288    */
289   public static Uniqueness getUniqueness(InstanceDescriptor descriptor, BeneratorContext context) {
290     if (descriptor instanceof IdDescriptor) {
291       return Uniqueness.ORDERED;
292     } else if (isUnique(descriptor, context)) {
293       return Uniqueness.SIMPLE;
294     } else {
295       return Uniqueness.NONE;
296     }
297   }
298 
299   /**
300    * Is unique boolean.
301    *
302    * @param descriptor the descriptor
303    * @param context    the context
304    * @return the boolean
305    */
306   public static boolean isUnique(InstanceDescriptor descriptor, BeneratorContext context) {
307     Boolean unique = descriptor.isUnique();
308     if (unique == null) {
309       unique = context.getGeneratorFactory().defaultUnique();
310     }
311     return unique;
312   }
313 
314   /**
315    * Gets separator.
316    *
317    * @param descriptor the descriptor
318    * @param context    the context
319    * @return the separator
320    */
321   public static char getSeparator(TypeDescriptor descriptor, BeneratorContext context) {
322     char separator = (context != null ? context.getDefaultSeparator() : ',');
323     if (!StringUtil.isEmpty(descriptor.getSeparator())) {
324       if (descriptor.getSeparator().length() > 1) {
325         throw new ConfigurationError("A CSV separator must be one character, but was: " + descriptor.getSeparator());
326       }
327       separator = descriptor.getSeparator().charAt(0);
328     }
329     return separator;
330   }
331 
332   /**
333    * Calculates the 'count' value.
334    *
335    * @param descriptor the descriptor
336    * @return the 'count' value. If a global 'maxCount' was set too, it returns the minimum of 'count' and 'maxCount'.
337    * If no 'count' value was specified, it returns null.
338    */
339   @SuppressWarnings("unchecked")
340   public static Expression<Long> getCount(InstanceDescriptor descriptor) {
341     Expression<Long> result = descriptor.getCount();
342     if (result != null) {
343       Expression<Long> globalMaxCount = getGlobalMaxCount();
344       if (globalMaxCount != null) {
345         result = new MinExpression<>(result, globalMaxCount);
346       }
347     }
348     return result;
349   }
350 
351   /**
352    * Gets min count.
353    *
354    * @param descriptor the descriptor
355    * @return the min count
356    */
357   public static Expression<Long> getMinCount(InstanceDescriptor descriptor) {
358     return getMinCount(descriptor, 1L);
359   }
360 
361   /**
362    * Gets min count.
363    *
364    * @param descriptor the descriptor
365    * @param defaultMin the default min
366    * @return the min count
367    */
368   @SuppressWarnings("unchecked")
369   public static Expression<Long> getMinCount(InstanceDescriptor descriptor, Long defaultMin) {
370     Expression<Long> result = null;
371     if (descriptor.getCount() != null) {
372       result = descriptor.getCount();
373     } else if (descriptor.getMinCount() != null) {
374       result = descriptor.getMinCount();
375     } else if (defaultMin != null) {
376       result = new ConstantExpression<>(defaultMin);
377     } else {
378       return new ConstantExpression<>(null);
379     }
380     Expression<Long> globalMaxCount = getGlobalMaxCount();
381     if (!ExpressionUtil.isNull(globalMaxCount)) {
382       result = new MinExpression<>(result, globalMaxCount);
383     }
384     return result;
385   }
386 
387   /**
388    * Gets max count.
389    *
390    * @param descriptor the descriptor
391    * @param defaultMax the default max
392    * @return the max count
393    */
394   @SuppressWarnings("unchecked")
395   public static Expression<Long> getMaxCount(InstanceDescriptor descriptor, Long defaultMax) {
396     Expression<Long> result = null;
397     if (descriptor.getCount() != null) {
398       result = descriptor.getCount();
399     } else if (descriptor.getMaxCount() != null) {
400       result = descriptor.getMaxCount();
401     } else if (descriptor instanceof ComponentDescriptor && defaultMax != null) {
402       result = new ConstantExpression<>(defaultMax);
403     } else {
404       return getGlobalMaxCount();
405     }
406     Expression<Long> globalMaxCount = getGlobalMaxCount();
407     if (!ExpressionUtil.isNull(globalMaxCount)) {
408       result = new MinExpression<>(result, globalMaxCount);
409     }
410     return result;
411   }
412 
413   private static Expression<Long> getGlobalMaxCount() {
414     return new GlobalMaxCountExpression();
415   }
416 
417   /**
418    * Gets count granularity.
419    *
420    * @param descriptor the descriptor
421    * @return the count granularity
422    */
423   public static Expression<Long> getCountGranularity(InstanceDescriptor descriptor) {
424     return (descriptor.getCountGranularity() != null ?
425         descriptor.getCountGranularity() :
426         new ConstantExpression<>(1L));
427   }
428 
429   /**
430    * Create string script converter converter.
431    *
432    * @param context the context
433    * @return the converter
434    */
435   public static Converter<String, String> createStringScriptConverter(BeneratorContext context) {
436     return new ConverterChain<>(
437         new ScriptConverterForStrings(context),
438         new ToStringConverter(null)
439     );
440   }
441 
442   /**
443    * Create dynamic count generator generator.
444    *
445    * @param descriptor the descriptor
446    * @param defaultMin the default min
447    * @param defaultMax the default max
448    * @param resetToMin the reset to min
449    * @param context    the context
450    * @return the generator
451    */
452   public static Generator<Long> createDynamicCountGenerator(final InstanceDescriptor descriptor,
453                                                             Long defaultMin, Long defaultMax, boolean resetToMin, BeneratorContext context) {
454     Expression<Long> count = DescriptorUtil.getCount(descriptor);
455     if (count != null) {
456       return new ExpressionBasedGenerator<>(count, Long.class);
457     } else {
458       final Expression<Long> minCount = DescriptorUtil.getMinCount(descriptor, defaultMin);
459       final Expression<Long> maxCount = DescriptorUtil.getMaxCount(descriptor, defaultMax);
460       final Expression<Long> countGranularity = DescriptorUtil.getCountGranularity(descriptor);
461       if (minCount.isConstant()) {
462         if (maxCount.isConstant() && descriptor.getCountDistribution() == null) {
463           // if minCount and maxCount are constants of the same value,
464           // then create a generator for a constant value
465           Long minCountValue = minCount.evaluate(context);
466           Long maxCountValue = maxCount.evaluate(context);
467           if (NullSafeComparator.equals(minCountValue, maxCountValue)) {
468             return new ConstantGenerator<>(minCountValue);
469           }
470         } else {
471           // if there is only a maxCount specified, then assume that
472           // the user actually wants to generate maxCount items but accepts less
473           return new ExpressionBasedGenerator<>(maxCount, Long.class);
474         }
475       }
476       // if no simplification was found yet, then create a fully featured distributed count generator
477       final Expression<Distribution> countDistribution =
478           FactoryUtil.getDistributionExpression(descriptor.getCountDistribution(), Uniqueness.NONE, true);
479       return new DynamicCountGenerator(minCount, maxCount, countGranularity, countDistribution,
480           ExpressionUtil.constant(false), resetToMin);
481     }
482   }
483 
484   /**
485    * Gets number detail.
486    *
487    * @param <T>        the type parameter
488    * @param descriptor the descriptor
489    * @param detailName the detail name
490    * @param targetType the target type
491    * @return the number detail
492    */
493   public static <T extends Number> T getNumberDetail(SimpleTypeDescriptor descriptor, String detailName, Class<T> targetType) {
494     try {
495       String detailValue = (String) descriptor.getDetailValue(detailName);
496       return (detailValue != null ? new String2NumberConverter<>(targetType).convert(detailValue) : null);
497     } catch (ConversionException e) {
498       throw new ConfigurationError(e);
499     }
500   }
501 
502   /**
503    * Parse component config.
504    *
505    * @param element the element
506    * @param type    the type
507    * @param context the context
508    */
509   public static void parseComponentConfig(Element element, TypeDescriptor type, BeneratorContext context) {
510     // parse child elements
511     ModelParser/ModelParser.html#ModelParser">ModelParser parser = new ModelParser(context);
512     int valueCount = 0;
513     for (Element child : XMLUtil.getChildElements(element)) {
514       String childType = XMLUtil.localName(child);
515       if (EL_VARIABLE.equals(childType)) {
516         parser.parseVariable(child, (VariableHolder) type);
517       } else if (COMPONENT_TYPES.contains(childType)) {
518         parser.parseComponent(child, (ComplexTypeDescriptor) type);
519       } else if (EL_VALUE.equals(childType)) {
520         parser.parseSimpleTypeArrayElement(child, (ArrayTypeDescriptor) type, valueCount++);
521       }
522     }
523   }
524 
525   /**
526    * Is nullable boolean.
527    *
528    * @param descriptor the descriptor
529    * @param context    the context
530    * @return the boolean
531    */
532   public static boolean isNullable(InstanceDescriptor descriptor, BeneratorContext context) {
533     Boolean nullable = descriptor.isNullable();
534     if (nullable != null) {
535       return nullable;
536     }
537     Double nullQuota = descriptor.getNullQuota();
538     if (nullQuota != null && nullQuota > 0) {
539       return true;
540     }
541     TypeDescriptor typeDescriptor = descriptor.getTypeDescriptor();
542     if (descriptor.getNullQuota() == null && typeDescriptor != null) {
543       // if nullability is not specified, but a source or generator, then do not generate nulls
544       if (typeDescriptor.getSource() != null || typeDescriptor.getGenerator() != null) {
545         return false;
546       }
547     }
548     return context.getDefaultsProvider().defaultNullable();
549   }
550 
551   /**
552    * Should nullify each nullable boolean.
553    *
554    * @param descriptor the descriptor
555    * @param context    the context
556    * @return the boolean
557    */
558   public static boolean shouldNullifyEachNullable(
559       InstanceDescriptor descriptor, BeneratorContext context) {
560     // nullQuota == 1?
561     Double nullQuota = descriptor.getNullQuota();
562     if (nullQuota != null && nullQuota == 1.) {
563       return true;
564     }
565     // nullable?
566     Boolean nullable = descriptor.isNullable();
567     if (nullable != null && !nullable) {
568       // nullable defaults to true
569       return false;
570     }
571     if (context.getDefaultsProvider().defaultNullQuota() < 1) {
572       return false; // if the factory requires nullification, it overrides the context setting
573     }
574     return (!descriptor.overwritesParent() && context.isDefaultNull());
575   }
576 
577   // helpers ---------------------------------------------------------------------------------------------------------
578 
579   /**
580    * Wrap with proxy generator.
581    *
582    * @param <T>        the type parameter
583    * @param generator  the generator
584    * @param descriptor the descriptor
585    * @return the generator
586    */
587   protected static <T> Generator<T> wrapWithProxy(Generator<T> generator, TypeDescriptor descriptor) {
588     generator = processOffset(generator, descriptor);
589     generator = processCyclic(generator, descriptor);
590     return generator;
591   }
592 
593   /**
594    * Process cyclic generator.
595    *
596    * @param <T>        the type parameter
597    * @param generator  the generator
598    * @param descriptor the descriptor
599    * @return the generator
600    */
601   public static <T> Generator<T> processCyclic(Generator<T> generator,
602                                                TypeDescriptor descriptor) {
603     boolean cyclic = descriptor.isCyclic() != null && descriptor.isCyclic();
604     if (cyclic) {
605       generator = WrapperFactory.applyCycler(generator);
606     }
607     return generator;
608   }
609 
610   /**
611    * Process offset generator.
612    *
613    * @param <T>        the type parameter
614    * @param generator  the generator
615    * @param descriptor the descriptor
616    * @return the generator
617    */
618   public static <T> Generator<T> processOffset(Generator<T> generator, TypeDescriptor descriptor) {
619     int offset = getOffset(descriptor);
620     if (offset > 0) {
621       generator = WrapperFactory.applyOffset(generator, offset);
622     }
623     return generator;
624   }
625 
626   /**
627    * Gets offset.
628    *
629    * @param descriptor the descriptor
630    * @return the offset
631    */
632   protected static int getOffset(TypeDescriptor descriptor) {
633     Integer offset = descriptor.getOffset();
634     return (offset != null ? offset : 0);
635   }
636 
637   /**
638    * Gets min length.
639    *
640    * @param descriptor the descriptor
641    * @return the min length
642    */
643   protected static Integer getMinLength(SimpleTypeDescriptor descriptor) {
644     Integer minLength = descriptor.getMinLength();
645     if (minLength == null) {
646       minLength = 0;
647     }
648     return minLength;
649   }
650 
651   /**
652    * Gets max length.
653    *
654    * @param descriptor       the descriptor
655    * @param defaultsProvider the defaults provider
656    * @return the max length
657    */
658   protected static Integer getMaxLength(SimpleTypeDescriptor descriptor, DefaultsProvider defaultsProvider) {
659     // evaluate max length
660     Integer maxLength = (Integer) descriptor.getDeclaredDetailValue(MAX_LENGTH);
661     if (maxLength == null) {
662       // maxLength was not set in this descriptor, so check the default value
663       maxLength = descriptor.getMaxLength();
664       if (maxLength == null) {
665         maxLength = defaultsProvider.defaultMaxLength();
666       }
667     }
668     return maxLength;
669   }
670 
671   /**
672    * Create null quota one generator generator.
673    *
674    * @param descriptor the descriptor
675    * @param context    the context
676    * @return the generator
677    */
678   public static Generator<?> createNullQuotaOneGenerator(InstanceDescriptor descriptor, BeneratorContext context) {
679     // check if nullQuota is 1
680     Double nullQuota = descriptor.getNullQuota();
681     if (nullQuota != null && nullQuota == 1.) {
682       return MetaGeneratorFactory.createNullGenerator(descriptor.getTypeDescriptor(), context);
683     } else {
684       return null;
685     }
686   }
687 
688   /**
689    * Derive type type descriptor.
690    *
691    * @param name       the name
692    * @param parentType the parent type
693    * @return the type descriptor
694    */
695   public static TypeDescriptorweller/model/data/TypeDescriptor.html#TypeDescriptor">TypeDescriptor deriveType(String name, TypeDescriptor parentType) {
696     if (parentType instanceof SimpleTypeDescriptor) {
697       return new SimpleTypeDescriptorta/SimpleTypeDescriptor.html#SimpleTypeDescriptor">SimpleTypeDescriptor(name, parentType.getProvider(), (SimpleTypeDescriptor) parentType);
698     } else if (parentType instanceof ComplexTypeDescriptor) {
699       return new ComplexTypeDescriptora/ComplexTypeDescriptor.html#ComplexTypeDescriptor">ComplexTypeDescriptor(name, parentType.getProvider(), (ComplexTypeDescriptor) parentType);
700     } else if (parentType instanceof ArrayTypeDescriptor) {
701       return new ArrayTypeDescriptorata/ArrayTypeDescriptor.html#ArrayTypeDescriptor">ArrayTypeDescriptor(name, parentType.getProvider(), (ArrayTypeDescriptor) parentType);
702     } else {
703       throw new UnsupportedOperationException("Cannot derive child type from " + parentType.getClass());
704     }
705   }
706 
707   /**
708    * The type Global max count expression.
709    */
710   static class GlobalMaxCountExpression implements Expression<Long> {
711     @Override
712     public boolean isConstant() {
713       return true;
714     }
715 
716     @Override
717     public Long evaluate(Context context) {
718       return ((BeneratorContext) context).getMaxCount();
719     }
720   }
721 
722 }