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.statement;
28  
29  import com.rapiddweller.benerator.Consumer;
30  import com.rapiddweller.benerator.composite.ComponentBuilder;
31  import com.rapiddweller.benerator.engine.BeneratorContext;
32  import com.rapiddweller.benerator.engine.BeneratorMonitor;
33  import com.rapiddweller.benerator.engine.CurrentProductGeneration;
34  import com.rapiddweller.benerator.engine.LifeCycleHolder;
35  import com.rapiddweller.benerator.engine.ResourceManager;
36  import com.rapiddweller.benerator.engine.ResourceManagerSupport;
37  import com.rapiddweller.benerator.engine.ScopedLifeCycleHolder;
38  import com.rapiddweller.benerator.engine.Statement;
39  import com.rapiddweller.benerator.engine.StatementUtil;
40  import com.rapiddweller.benerator.wrapper.ProductWrapper;
41  import com.rapiddweller.common.Context;
42  import com.rapiddweller.common.ErrorHandler;
43  import com.rapiddweller.common.IOUtil;
44  import com.rapiddweller.common.MessageHolder;
45  import com.rapiddweller.common.Resettable;
46  import com.rapiddweller.script.Expression;
47  import com.rapiddweller.script.expression.ExpressionUtil;
48  import com.rapiddweller.task.PageListener;
49  import com.rapiddweller.task.Task;
50  import com.rapiddweller.task.TaskResult;
51  
52  import java.io.Closeable;
53  import java.util.ArrayList;
54  import java.util.List;
55  import java.util.concurrent.atomic.AtomicBoolean;
56  
57  /**
58   * Task that creates one data set instance per run() invocation and sends it to the specified consumer.<br/><br/>
59   * Created: 01.02.2008 14:39:11
60   *
61   * @author Volker Bergmann
62   */
63  public class GenerateAndConsumeTask implements Task, PageListener, ResourceManager, MessageHolder {
64  
65    private final String taskName;
66    private BeneratorContext context;
67    private final ResourceManager resourceManager;
68  
69    /**
70     * The Statements.
71     */
72    protected final List<Statement> statements;
73    private final List<ScopedLifeCycleHolder> scopeds;
74    private Expression<Consumer> consumerExpr;
75  
76    private final AtomicBoolean initialized;
77    private Consumer consumer;
78    private String message;
79    private final String productName;
80  
81    /**
82     * Instantiates a new Generate and consume task.
83     *
84     * @param taskName    the task name
85     * @param productName the product name
86     */
87    public GenerateAndConsumeTask(String taskName, String productName) {
88      this.taskName = taskName;
89      this.productName = productName;
90      this.resourceManager = new ResourceManagerSupport();
91      this.initialized = new AtomicBoolean(false);
92      this.statements = new ArrayList<>();
93      this.scopeds = new ArrayList<>();
94    }
95  
96    // interface -------------------------------------------------------------------------------------------------------
97  
98    /**
99     * Add statement.
100    *
101    * @param statement the statement
102    */
103   public void addStatement(Statement statement) {
104     this.statements.add(statement);
105   }
106 
107   /**
108    * Sets statements.
109    *
110    * @param statements the statements
111    */
112   public void setStatements(List<Statement> statements) {
113     this.statements.clear();
114     for (Statement statement : statements) {
115       this.addStatement(statement);
116     }
117   }
118 
119   /**
120    * Gets resource manager.
121    *
122    * @return the resource manager
123    */
124   public ResourceManager getResourceManager() {
125     return resourceManager;
126   }
127 
128   /**
129    * Sets consumer.
130    *
131    * @param consumerExpr the consumer expr
132    */
133   public void setConsumer(Expression<Consumer> consumerExpr) {
134     this.consumerExpr = consumerExpr;
135   }
136 
137   /**
138    * Gets consumer.
139    *
140    * @return the consumer
141    */
142   public Consumer getConsumer() {
143     return consumer;
144   }
145 
146   /**
147    * Init.
148    *
149    * @param context the context
150    */
151   public void init(BeneratorContext context) {
152     synchronized (initialized) {
153       if (!initialized.get()) {
154         this.context = context;
155         this.consumer = ExpressionUtil.evaluate(consumerExpr, context);
156         resourceManager.addResource(consumer);
157         injectConsumptionStart();
158         injectConsumptionEnd();
159         initialized.set(true);
160         initStatements(context);
161         checkScopes(statements, context);
162       }
163     }
164   }
165 
166   /**
167    * Gets product name.
168    *
169    * @return the product name
170    */
171   public String getProductName() {
172     return productName;
173   }
174 
175   /**
176    * Gets recent product.
177    *
178    * @return the recent product
179    */
180   public ProductWrapper<?> getRecentProduct() {
181     return context.getCurrentProduct();
182   }
183 
184   // Task interface implementation -----------------------------------------------------------------------------------
185 
186   @Override
187   public String getTaskName() {
188     return taskName;
189   }
190 
191   @Override
192   public boolean isThreadSafe() {
193     return false;
194   }
195 
196   @Override
197   public boolean isParallelizable() {
198     return false;
199   }
200 
201   @Override
202   public TaskResult execute(Context ctx, ErrorHandler errorHandler) {
203     message = null;
204     if (!initialized.get()) {
205       init((BeneratorContext) ctx);
206     }
207     try {
208       boolean success = true;
209       for (int i = 0; i < statements.size(); i++) {
210         Statement statement = statements.get(i);
211         success &= statement.execute(context);
212         if (!success && (statement instanceof ValidationStatement)) {
213           i = -1; // if the product is not valid, restart with the first statement
214           success = true;
215           continue;
216         }
217         if (!success) {
218           if (statement instanceof MessageHolder) {
219             this.message = ((MessageHolder) statement).getMessage();
220           }
221           break;
222         }
223       }
224       if (success) {
225         BeneratorMonitor.INSTANCE.countGenerations(1);
226       }
227       enqueueResets(statements);
228       Thread.yield();
229       return (success ? TaskResult.EXECUTING : TaskResult.UNAVAILABLE);
230     } catch (Exception e) {
231       errorHandler.handleError("Error in execution of task " + getTaskName(), e);
232       return TaskResult.EXECUTING; // stay available if the ErrorHandler has not canceled execution
233     }
234   }
235 
236   /**
237    * Reset.
238    */
239   public void reset() {
240     for (Statement statement : statements) {
241       statement = StatementUtil.getRealStatement(statement, context);
242       if (statement instanceof ScopedLifeCycleHolder) {
243         ScopedLifeCycleHoldercom/rapiddweller/benerator/engine/ScopedLifeCycleHolder.html#ScopedLifeCycleHolder">ScopedLifeCycleHolder holder = (ScopedLifeCycleHolder) statement;
244         holder.resetIfNeeded();
245       } else if (statement instanceof Resettable) {
246         ((Resettable) statement).reset();
247       }
248     }
249   }
250 
251   @Override
252   public void close() {
253     // close sub statements
254     for (Statement statement : statements) {
255       statement = StatementUtil.getRealStatement(statement, context);
256       if (statement instanceof Closeable) {
257         IOUtil.close((Closeable) statement);
258       }
259     }
260     // close resource manager
261     resourceManager.close();
262   }
263 
264 
265   // PageListener interface ------------------------------------------------------------------------------------------
266 
267   @Override
268   public void pageStarting() {
269     // nothing special to do on page start
270   }
271 
272   @Override
273   public void pageFinished() {
274     IOUtil.flush(consumer);
275   }
276 
277 
278   // ResourceManager interface ---------------------------------------------------------------------------------------
279 
280   @Override
281   public boolean addResource(Closeable resource) {
282     return resourceManager.addResource(resource);
283   }
284 
285   // MessageHolder interface -----------------------------------------------------------------------------------------
286 
287   @Override
288   public String getMessage() {
289     return message;
290   }
291 
292   // java.lang.Object overrides --------------------------------------------------------------------------------------
293 
294   @Override
295   public String toString() {
296     return getClass().getSimpleName() + '(' + taskName + ')';
297   }
298 
299   // private helpers -------------------------------------------------------------------------------------------------
300 
301   private void injectConsumptionStart() {
302     // find last sub member generation...
303     int lastMemberIndex = -1;
304     for (int i = statements.size() - 1; i >= 0; i--) {
305       Statement statement = statements.get(i);
306       if (statement instanceof ComponentBuilder || statement instanceof CurrentProductGeneration
307           || statement instanceof ValidationStatement || statement instanceof ConversionStatement) {
308         lastMemberIndex = i;
309         break;
310       }
311     }
312     // ...and insert consumption start statement immediately after that one
313     ConsumptionStatementConsumptionStatement.html#ConsumptionStatement">ConsumptionStatement consumption = new ConsumptionStatement(consumer, true, false);
314     statements.add(lastMemberIndex + 1, consumption);
315   }
316 
317   private void injectConsumptionEnd() {
318     // find last sub generation statement...
319     int lastSubGenIndex = statements.size() - 1;
320     for (int i = statements.size() - 1; i >= 0; i--) {
321       Statement statement = statements.get(i);
322       if (statement instanceof GenerateOrIterateStatement) {
323         lastSubGenIndex = i;
324         break;
325       }
326     }
327     // ...and insert consumption finish statement immediately after that one
328     ConsumptionStatementConsumptionStatement.html#ConsumptionStatement">ConsumptionStatement consumption = new ConsumptionStatement(consumer, false, true);
329     statements.add(lastSubGenIndex + 1, consumption);
330   }
331 
332   /**
333    * Init statements.
334    *
335    * @param context the context
336    */
337   public void initStatements(BeneratorContext context) {
338     for (Statement statement : statements) {
339       statement = StatementUtil.getRealStatement(statement, context);
340       if (statement instanceof LifeCycleHolder) {
341         ((LifeCycleHolder) statement).init(context);
342       }
343     }
344   }
345 
346   private void checkScopes(List<Statement> statements, BeneratorContext scopeContext) {
347     for (Statement statement : statements) {
348       statement = StatementUtil.getRealStatement(statement, scopeContext);
349       if (statement instanceof ScopedLifeCycleHolder) {
350         ScopedLifeCycleHoldercom/rapiddweller/benerator/engine/ScopedLifeCycleHolder.html#ScopedLifeCycleHolder">ScopedLifeCycleHolder holder = (ScopedLifeCycleHolder) statement;
351         String scope = holder.getScope();
352         if (scope == null || productName.equals(scope)) {
353           scopeds.add(holder);
354         }
355       } else if (statement instanceof GenerateOrIterateStatement) {
356         GenerateOrIterateStatementweller/benerator/engine/statement/GenerateOrIterateStatement.html#GenerateOrIterateStatement">GenerateOrIterateStatement subGenerate = (GenerateOrIterateStatement) statement;
357         checkScopes(subGenerate.getTask().statements, subGenerate.getChildContext());
358       }
359     }
360   }
361 
362   private void enqueueResets(List<Statement> statements) {
363     for (ScopedLifeCycleHolder scoped : scopeds) {
364       scoped.setResetNeeded(true);
365     }
366   }
367 
368 }