/* * (c) Copyright 2007-2012 by Volker Bergmann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, is permitted under the terms of the * GNU General Public License. * * For redistributing this software or a derivative work under a license other * than the GPL-compatible Free Software License as defined by the Free * Software Foundation or approved by OSI, you must first obtain a commercial * license to this software product from Volker Bergmann. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS, * REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE * HEREBY EXCLUDED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ package org.databene.benerator.engine.statement; import java.io.Closeable; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import org.databene.benerator.Consumer; import org.databene.benerator.composite.ComponentBuilder; import org.databene.benerator.engine.BeneratorContext; import org.databene.benerator.engine.BeneratorMonitor; import org.databene.benerator.engine.CurrentProductGeneration; import org.databene.benerator.engine.LifeCycleHolder; import org.databene.benerator.engine.ScopedLifeCycleHolder; import org.databene.benerator.engine.ResourceManager; import org.databene.benerator.engine.ResourceManagerSupport; import org.databene.benerator.engine.Statement; import org.databene.benerator.engine.StatementUtil; import org.databene.benerator.wrapper.ProductWrapper; import org.databene.commons.Context; import org.databene.commons.ErrorHandler; import org.databene.commons.IOUtil; import org.databene.commons.MessageHolder; import org.databene.commons.Resettable; import org.databene.script.Expression; import org.databene.script.expression.ExpressionUtil; import org.databene.task.PageListener; import org.databene.task.Task; import org.databene.task.TaskResult; /** * Task that creates one data set instance per run() invocation and sends it to the specified consumer.<br/><br/> * Created: 01.02.2008 14:39:11 * @author Volker Bergmann */ public class GenerateAndConsumeTask implements Task, PageListener, ResourceManager, MessageHolder { private String taskName; private BeneratorContext context; private ResourceManager resourceManager; private List<Statement> statements; private List<LifeCycleHolder> scopeds; private Expression<Consumer> consumerExpr; private volatile AtomicBoolean initialized; private Consumer consumer; private String message; private String productName; public GenerateAndConsumeTask(String taskName, String productName) { this.taskName = taskName; this.productName = productName; this.resourceManager = new ResourceManagerSupport(); this.initialized = new AtomicBoolean(false); this.statements = new ArrayList<Statement>(); this.scopeds = new ArrayList<LifeCycleHolder>(); } // interface ------------------------------------------------------------------------------------------------------- public void addStatement(Statement statement) { this.statements.add(statement); } public void setStatements(List<Statement> statements) { this.statements.clear(); for (Statement statement : statements) this.addStatement(statement); } public ResourceManager getResourceManager() { return resourceManager; } public void setConsumer(Expression<Consumer> consumerExpr) { this.consumerExpr = consumerExpr; } public Consumer getConsumer() { return consumer; } public void init(BeneratorContext context) { synchronized (initialized) { if (!initialized.get()) { this.context = context; this.consumer = ExpressionUtil.evaluate(consumerExpr, context); resourceManager.addResource(consumer); injectConsumptionStart(); injectConsumptionEnd(); initialized.set(true); initStatements(context); checkScopes(statements); } } } public String getProductName() { return productName; } public ProductWrapper<?> getRecentProduct() { return context.getCurrentProduct(); } // Task interface implementation ----------------------------------------------------------------------------------- public String getTaskName() { return taskName; } public boolean isThreadSafe() { return false; } public boolean isParallelizable() { return false; } public TaskResult execute(Context ctx, ErrorHandler errorHandler) { message = null; if (!initialized.get()) init((BeneratorContext) ctx); try { boolean success = true; for (int i = 0; i < statements.size(); i++) { Statement statement = statements.get(i); success &= statement.execute(context); if (!success && (statement instanceof ValidationStatement)) { i = -1; // if the product is not valid, restart with the first statement success = true; continue; } if (!success) { if (statement instanceof MessageHolder) this.message = ((MessageHolder) statement).getMessage(); break; } } if (success) BeneratorMonitor.INSTANCE.countGenerations(1); Thread.yield(); return (success ? TaskResult.EXECUTING : TaskResult.UNAVAILABLE); } catch (Exception e) { errorHandler.handleError("Error in execution of task " + getTaskName(), e); return TaskResult.EXECUTING; // stay available if the ErrorHandler has not canceled execution } } public void reset() { enqueueResets(statements); performLocalResets(); } public void close() { // close sub statements for (Statement statement : statements) { statement = StatementUtil.getRealStatement(statement, context); if (statement instanceof Closeable) IOUtil.close((Closeable) statement); } // close resource manager resourceManager.close(); } // PageListener interface ------------------------------------------------------------------------------------------ public void pageStarting() { // nothing special to do on page start } public void pageFinished() { IOUtil.flush(consumer); } // ResourceManager interface --------------------------------------------------------------------------------------- public boolean addResource(Closeable resource) { return resourceManager.addResource(resource); } // MessageHolder interface ----------------------------------------------------------------------------------------- public String getMessage() { return message; } // java.lang.Object overrides -------------------------------------------------------------------------------------- @Override public String toString() { return getClass().getSimpleName() + '(' + taskName + ')'; } // private helpers ------------------------------------------------------------------------------------------------- private void injectConsumptionStart() { // find last sub member generation... int lastMemberIndex = - 1; for (int i = statements.size() - 1; i >= 0; i--) { Statement statement = statements.get(i); if (statement instanceof ComponentBuilder || statement instanceof CurrentProductGeneration || statement instanceof ValidationStatement || statement instanceof ConversionStatement) { lastMemberIndex = i; break; } } // ...and insert consumption start statement immediately after that one ConsumptionStatement consumption = new ConsumptionStatement(consumer, true, false); statements.add(lastMemberIndex + 1, consumption); } private void injectConsumptionEnd() { // find last sub generation statement... int lastSubGenIndex = statements.size() - 1; for (int i = statements.size() - 1; i >= 0; i--) { Statement statement = statements.get(i); if (statement instanceof GenerateOrIterateStatement) { lastSubGenIndex = i; break; } } // ...and insert consumption finish statement immediately after that one ConsumptionStatement consumption = new ConsumptionStatement(consumer, false, true); statements.add(lastSubGenIndex + 1, consumption); } public void initStatements(BeneratorContext context) { for (Statement statement : statements) { statement = StatementUtil.getRealStatement(statement, context); if (statement instanceof LifeCycleHolder) ((LifeCycleHolder) statement).init(context); } } private void checkScopes(List<Statement> statements) { for (Statement statement : statements) { statement = StatementUtil.getRealStatement(statement, context); if (statement instanceof ScopedLifeCycleHolder) { ScopedLifeCycleHolder holder = (ScopedLifeCycleHolder) statement; String scope = holder.getScope(); if (scope == null || productName.equals(scope)) scopeds.add(holder); } else if (statement instanceof GenerateOrIterateStatement) { GenerateOrIterateStatement subGenerate = (GenerateOrIterateStatement) statement; checkScopes(subGenerate.getTask().statements); } } } private void enqueueResets(List<Statement> statements) { for (LifeCycleHolder scoped : scopeds) scoped.reset(); } private void performLocalResets() { for (Statement statement : statements) { statement = StatementUtil.getRealStatement(statement, context); if (statement instanceof ScopedLifeCycleHolder) { ScopedLifeCycleHolder holder = (ScopedLifeCycleHolder) statement; holder.resetIfNeeded(); } else if (statement instanceof Resettable) { ((Resettable) statement).reset(); } } } }