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.parser.xml;
28  
29  import com.rapiddweller.benerator.Generator;
30  import com.rapiddweller.benerator.engine.DescriptorConstants;
31  import com.rapiddweller.benerator.engine.Statement;
32  import com.rapiddweller.benerator.engine.expression.ScriptableExpression;
33  import com.rapiddweller.benerator.engine.expression.context.ContextReference;
34  import com.rapiddweller.benerator.engine.statement.IfStatement;
35  import com.rapiddweller.benerator.engine.statement.SetSettingStatement;
36  import com.rapiddweller.benerator.wrapper.ProductWrapper;
37  import com.rapiddweller.common.CollectionUtil;
38  import com.rapiddweller.common.ConfigurationError;
39  import com.rapiddweller.common.Context;
40  import com.rapiddweller.common.ParseException;
41  import com.rapiddweller.common.xml.XMLUtil;
42  import com.rapiddweller.script.DatabeneScriptParser;
43  import com.rapiddweller.script.Expression;
44  import com.rapiddweller.script.expression.CompositeExpression;
45  import com.rapiddweller.script.expression.DynamicExpression;
46  import com.rapiddweller.script.expression.ExpressionUtil;
47  import com.rapiddweller.script.expression.IsNullExpression;
48  import org.w3c.dom.Element;
49  
50  import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_DEFAULT;
51  import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_NAME;
52  import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_REF;
53  import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_SOURCE;
54  import static com.rapiddweller.benerator.engine.DescriptorConstants.ATT_VALUE;
55  
56  /**
57   * Parses a &lt;Property&gt; element in a Benerator descriptor file.<br/><br/>
58   * Created: 25.10.2009 00:58:53
59   *
60   * @author Volker Bergmann
61   * @since 0.6.0
62   */
63  public class SettingParser extends AbstractBeneratorDescriptorParser {
64  
65    /**
66     * Instantiates a new Setting parser.
67     */
68    public SettingParser() {
69      super(DescriptorConstants.EL_SETTING, CollectionUtil.toSet(ATT_NAME),
70          CollectionUtil.toSet(ATT_DEFAULT, ATT_VALUE, ATT_REF, ATT_SOURCE));
71    }
72  
73    @Override
74    public Statementcom/rapiddweller/benerator/engine/Statement.html#Statement">Statement doParse(Element element, Statement[] parentPath, BeneratorParseContext context) {
75      String propertyName = element.getAttribute(ATT_NAME);
76      if (element.hasAttribute(ATT_DEFAULT)) {
77        return parseDefault(propertyName, element.getAttribute(ATT_DEFAULT));
78      } else {
79        Expression<?> valueEx = parseValue(element);
80        return new SetSettingStatement(propertyName, valueEx);
81      }
82    }
83  
84    /**
85     * Parse value expression.
86     *
87     * @param element the element
88     * @return the expression
89     */
90    @SuppressWarnings({"unchecked", "rawtypes"})
91    public static Expression<?> parseValue(Element element) {
92      if (element.hasAttribute(ATT_VALUE)) {
93        return DescriptorParserUtil.parseScriptableStringAttribute(ATT_VALUE, element);
94      } else if (element.hasAttribute(ATT_REF)) {
95        return new ContextReference(element.getAttribute(ATT_REF));
96      } else if (element.hasAttribute(ATT_SOURCE)) {
97        return parseSource(element.getAttribute(ATT_SOURCE));
98      } else { // map child elements to a collection or array
99        Element[] childElements = XMLUtil.getChildElements(element);
100       Expression[] subExpressions = new Expression[childElements.length];
101       for (int j = 0; j < childElements.length; j++) {
102         subExpressions[j] = BeanParser.parseBeanExpression(childElements[j]);
103       }
104       switch (subExpressions.length) {
105         case 0:
106           throw new ConfigurationError("No valid property spec: " + XMLUtil.formatShort(element));
107         case 1:
108           return subExpressions[0];
109         default:
110           return new CompositeExpression<Object, Object>(subExpressions) {
111             @Override
112             public Object[] evaluate(Context context) {
113               return ExpressionUtil.evaluateAll(terms, context);
114             }
115           };
116       }
117     }
118   }
119 
120   @SuppressWarnings({"unchecked", "rawtypes"})
121   private static Expression<?> parseSource(String source) {
122     try {
123       return new SourceExpression(DatabeneScriptParser.parseBeanSpec(source));
124     } catch (ParseException e) {
125       throw new ConfigurationError("Error parsing property source expression: " + source, e);
126     }
127   }
128 
129   private static Statement parseDefault(String propertyName, String defaultValue) {
130     try {
131       ScriptableExpressionScriptableExpression.html#ScriptableExpression">ScriptableExpression valueExpression = new ScriptableExpression(defaultValue, null);
132       SetSettingStatementSetSettingStatement.html#SetSettingStatement">SetSettingStatement setterStatement = new SetSettingStatement(propertyName, valueExpression);
133       Expression<Boolean> condition = new IsNullExpression(new ContextReference(propertyName));
134       return new IfStatement(condition, setterStatement);
135     } catch (ParseException e) {
136       throw new ConfigurationError("Error parsing property default value expression: " + defaultValue, e);
137     }
138   }
139 
140   /**
141    * Evaluates a 'source' expression to a Generator.<br/><br/>
142    * Created: 26.10.2009 08:38:44
143    *
144    * @param <E> the type parameter
145    * @author Volker Bergmann
146    * @since 0.6.0
147    */
148   public static class SourceExpression<E> extends DynamicExpression<E> {
149 
150     /**
151      * The Source.
152      */
153     final Expression<Generator<E>> source;
154 
155     /**
156      * Instantiates a new Source expression.
157      *
158      * @param source the source
159      */
160     public SourceExpression(Expression<Generator<E>> source) {
161       this.source = source;
162     }
163 
164     @Override
165     public E evaluate(Context context) {
166       Generator<E> generator = source.evaluate(context);
167       ProductWrapper<E> wrapper = generator.generate(new ProductWrapper<>());
168       if (wrapper == null) {
169         throw new ConfigurationError("Generator not available: " + generator);
170       }
171       return wrapper.unwrap();
172     }
173 
174   }
175 
176 }