/* * Copyright (C) 2006-2016 DLR, Germany * * All rights reserved * * http://www.rcenvironment.de/ */ package de.rcenvironment.core.component.model.spi; import de.rcenvironment.core.component.api.ComponentException; import de.rcenvironment.core.component.api.LoopComponentConstants; import de.rcenvironment.core.datamodel.api.EndpointCharacter; import de.rcenvironment.core.datamodel.types.api.BooleanTD; import de.rcenvironment.core.datamodel.types.api.InternalTD; /** * The {@link AbstractNestedLoopComponent} is an abstract class that must be used for components * that should be able to run in a nested loop. It defines the lifecycle for a nested component for * being used as inner or as oter loop component. If the scheduling from the * {@link DefaultComponent} should be used, the "callDefaultScheduling" method can be used. * * Note that this class redefines the life cycle of the {@link DefaultComponent}. The standard life * cycle methods like runStep are overwritten and made final, because they must not be overwritten * by the sub class. To implement the component's individual logic, there are custom abstract * methods of all lifecycle methods. * * If this class is used for a component, there are some more things that must be used: * <ul> * <li> * In the component's GUI, the {@link NestedLoopSection} must be added</li> * <li> * The component must have a {@link BooleanTD} output, which is used in this class for telling inner * loops, if the outer loop is finished. This output's name is what the getLoopFinishedEnpointName() * method must return.</li> * <li> * The component must define the input "Outer loop done" as boolean, which will be created by the * {@link NestedLoopSection}</li> * </ul> * * @author Sascha Zur * @author Doreen Seider */ public abstract class AbstractNestedLoopComponent extends AbstractLoopComponent { private boolean isInInnerLoop; private boolean isFinallyDone = false; private boolean isReset; @Override public void startComponentSpecific() throws ComponentException { isInInnerLoop = Boolean.valueOf(componentContext.getConfigurationValue(LoopComponentConstants.CONFIG_KEY_IS_NESTED_LOOP)); startNestedComponentSpecific(); } @Override public void processInputsComponentSpecific() throws ComponentException { if (loopFailureRequested) { isReset = true; sendReset(); } else { processInputsNestedComponentSpecific(); if (isDone()) { loopIsFinished(); } else { sendValuesNestedComponentSpecific(); } } } @Override public void resetComponentSpecific() throws ComponentException { resetNestedComponentSpecific(); startNestedComponentSpecific(); isReset = false; } @Override protected boolean isDone() { return isDoneNestedComponentSpecific() || (!isInInnerLoop() && isFinallyDone()); } @Override protected boolean isFinallyDone() { return isFinallyDone; } protected boolean isInInnerLoop() { return isInInnerLoop; } @Override protected boolean isReset() { return isReset; } private void loopIsFinished() throws ComponentException { if (isInInnerLoop) { isReset = true; sendReset(); } else { outerLoopIsFinished(); } } private void outerLoopIsFinished() throws ComponentException { finishLoop(true); } @Override protected void finishLoopComponentSpecific(boolean outerLoopFinished) throws ComponentException { finishLoop(outerLoopFinished); } private void finishLoop(boolean outerLoopFinished) throws ComponentException { if (outerLoopFinished) { isFinallyDone = true; if (!isInInnerLoop) { sendFinalValues(); finishLoopNestedComponentSpecific(); } } else { sendFinalValues(); finishLoopNestedComponentSpecific(); } } /** * Method is called after the {@link AbstractNestedLoopComponent} has initialized all it needs. * It replaces the original runInitial() Method. * * @return true, if component is not finished. * @throws ComponentException */ protected void startNestedComponentSpecific() throws ComponentException {} /** * This hook is for implementing the component logic. * * @param newInput * @param inputValues * @return * @throws ComponentException */ protected void processInputsNestedComponentSpecific() throws ComponentException {} /** * Component dependent part when a loop is reset if it is an inner loop. */ protected abstract void resetNestedComponentSpecific(); /** * Component dependent part when a loop is finished. */ protected abstract void finishLoopNestedComponentSpecific(); /** * @return whether the components logic is finished (no more runSteps) or not. */ protected abstract boolean isDoneNestedComponentSpecific(); /** * If needed, the component should send e.g. optimized values at this point. * * @throws ComponentException */ protected abstract void sendFinalValues() throws ComponentException; /** * Send {@link InternalTD} to all self loop outputs. */ protected void sendReset() { for (String output : componentContext.getOutputs()) { if (componentContext.getOutputCharacter(output).equals(EndpointCharacter.SAME_LOOP)) { componentContext.resetOutput(output); } } } /** * This method consumes a start value from an input. Receiving new values should be individual * for every component. */ protected abstract void sendValuesNestedComponentSpecific(); }