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.sample;
28  
29  import com.rapiddweller.benerator.Generator;
30  import com.rapiddweller.benerator.GeneratorContext;
31  import com.rapiddweller.benerator.IllegalGeneratorStateException;
32  import com.rapiddweller.benerator.InvalidGeneratorSetupException;
33  import com.rapiddweller.benerator.util.UnsafeNonNullGenerator;
34  import com.rapiddweller.benerator.wrapper.ProductWrapper;
35  import com.rapiddweller.common.ConfigurationError;
36  import com.rapiddweller.common.ParseException;
37  import com.rapiddweller.common.StringUtil;
38  import com.rapiddweller.script.DatabeneScriptParser;
39  import com.rapiddweller.script.WeightedTransition;
40  
41  import java.util.HashMap;
42  import java.util.Map;
43  
44  /**
45   * Generates states as configured by a state machine.<br/>
46   * <br/>
47   * Created at 17.07.2009 05:41:47
48   *
49   * @param <E> the type parameter
50   * @author Volker Bergmann
51   * @since 0.6.0
52   */
53  public class StateGenerator<E> extends UnsafeNonNullGenerator<E> {
54  
55    private final Class<E> generatedType;
56    private final Map<E, AttachedWeightSampleGenerator<E>> transitionsGenerators;
57    private E nextState;
58  
59    // initialization --------------------------------------------------------------------------------------------------
60  
61    /**
62     * Instantiates a new State generator.
63     */
64    public StateGenerator() {
65      this((String) null);
66    }
67  
68    /**
69     * Instantiates a new State generator.
70     *
71     * @param transitionSpec the transition spec
72     */
73    @SuppressWarnings("unchecked")
74    public StateGenerator(String transitionSpec) {
75      this((Class<E>) Object.class);
76      setTransitions(transitionSpec);
77    }
78  
79    /**
80     * Instantiates a new State generator.
81     *
82     * @param generatedType the generated type
83     */
84    public StateGenerator(Class<E> generatedType) {
85      this.generatedType = generatedType;
86      this.transitionsGenerators = new HashMap<>();
87      this.nextState = null;
88    }
89  
90    /**
91     * Sets transitions.
92     *
93     * @param transitionSpec the transition spec
94     */
95    @SuppressWarnings("unchecked")
96    public void setTransitions(String transitionSpec) {
97      if (StringUtil.isEmpty(transitionSpec)) {
98        transitionsGenerators.clear();
99        return;
100     }
101     try {
102       WeightedTransition[] ts = DatabeneScriptParser.parseTransitionList(transitionSpec);
103       for (WeightedTransition t : ts) {
104         addTransition((E) t.getFrom(), (E) t.getTo(), t.getWeight());
105       }
106     } catch (ParseException e) {
107       throw new ConfigurationError("Error parsing state machine specification: " + transitionSpec, e);
108     }
109   }
110 
111   /**
112    * Add transition.
113    *
114    * @param from   the from
115    * @param to     the to
116    * @param weight the weight
117    */
118   public void addTransition(E from, E to, double weight) {
119     AttachedWeightSampleGenerator<E> subGenerator = transitionsGenerators.get(from);
120     if (subGenerator == null) {
121       subGenerator = new AttachedWeightSampleGenerator<>(generatedType);
122       transitionsGenerators.put(from, subGenerator);
123     }
124     subGenerator.addSample(to, weight);
125   }
126 
127   // Generator interface implementation ------------------------------------------------------------------------------
128 
129   @Override
130   public Class<E> getGeneratedType() {
131     return generatedType;
132   }
133 
134   @Override
135   public void init(GeneratorContext context) throws InvalidGeneratorSetupException {
136     assertNotInitialized();
137     boolean hasEndTransition = false;
138     for (AttachedWeightSampleGenerator<E> tmp : transitionsGenerators.values()) {
139       if (tmp.containsSample(null)) {
140         hasEndTransition = true;
141         break;
142       }
143     }
144     if (!hasEndTransition) {
145       throw new InvalidGeneratorSetupException("No final state defined for " + this);
146     }
147     for (Generator<E> tmp : transitionsGenerators.values()) {
148       tmp.init(context);
149     }
150     AttachedWeightSampleGenerator<E> gen = this.transitionsGenerators.get(null);
151     nextState = gen.generate(getResultWrapper()).unwrap();
152     super.init(context);
153   }
154 
155   @Override
156   public E generate() {
157     if (nextState == null) {
158       return null;
159     }
160     E result = nextState;
161     AttachedWeightSampleGenerator<E> transitionGenerator = transitionsGenerators.get(nextState);
162     ProductWrapper<E> wrapper = transitionGenerator.generate(getResultWrapper());
163     nextState = (wrapper != null ? wrapper.unwrap() : null);
164     return result;
165   }
166 
167   @Override
168   public void reset() throws IllegalGeneratorStateException {
169     AttachedWeightSampleGenerator<E> transitionGenerator = this.transitionsGenerators.get(null);
170     ProductWrapper<E> wrapper = transitionGenerator.generate(getResultWrapper());
171     nextState = (wrapper != null ? wrapper.unwrap() : null);
172     super.reset();
173   }
174 
175   @Override
176   public void close() {
177     super.close();
178   }
179 
180   // java.lang.Object overrides --------------------------------------------------------------------------------------
181 
182   @Override
183   public String toString() {
184     return getClass().getSimpleName() + transitionsGenerators;
185   }
186 
187 }