java.lang.Object
com.tccc.kos.ext.dispense.pipeline.ingredient.ops.PumpOp
All Implemented Interfaces:
com.tccc.kos.commons.util.Abortable, com.tccc.kos.commons.util.Cancelable, com.tccc.kos.commons.util.Terminable, Cloneable
Direct Known Subclasses:
DelayOp, PumpEventPumpOp

public abstract class PumpOp extends Object implements Cloneable, com.tccc.kos.commons.util.Terminable
Base class for all operations that can be executed by the IngredientPipelineService. These are typically loaded by PumpIntentFactory. When an intent is requested, the associated operations are cloned for actual use. This means that operations must be cloneable and contain a reasonable initial state.

After an operation is cloned, the associated Pump and IngredientPipelineService will be set, allowing them to be used when buildFuture() is called and while the operation is running.

This base class includes support for several properties that subclasses can choose to leverage:

  • rate : Many operations require a specified rate. This base class supports both getRate() and getEffectiveRate(). The effective rate returns the nominal rate of the pump if the specified rate is zero. The effective rate should be used to allow intents to be written that don't specify a rates. This is particularly useful when working with valves, where the rate is ignored since a valve has a fixed flow rate.
  • dilution : When working with highly concentrated ingredients, such as micro-dosed ingredients, they should generally be poured with a dilution ingredient such as water. When working with micro-dosed hardware, IngredientPipelineService can be configured with a dilution pump, and setting the dilution flag in an operation causes the dilution pump to run concurrently.

The buildFuture() method can only be called once per operation instance, as operations are not reusable, which is why they are cloned from the intent before use. While many use cases rely on future callbacks which have access to the future, there are cases where the future is not easily accessible. To facilitate these use cases, getFuture() returns the future generated by buildFuture().

The start() and stop() methods will be called using START and COMPLETE callbacks on the future which provides an easy way to add pre- and post-logic to an operation in a base class. It is important for all subclasses that override these methods to call the super versions to ensure that critical functionality is not inadvertantly not called. For example, dilution support leverages these methods so not calling these super methods when overriding will break dilution.

Since:
1.0
Version:
2023-01-21
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static class 
    PumpOp grant
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final String
     
  • Constructor Summary

    Constructors
    Constructor
    Description
     
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    abort(String reason)
    Abort the intent that the pumpOp is part of.
    void
    Add a grant to the list of required grants.
    abstract com.tccc.kos.commons.util.concurrent.future.FutureWork
    buildFuture(com.tccc.kos.commons.util.concurrent.future.FutureWork intentFuture)
    Returns a future which encapsulates the work that this operation must perform.
    void
    cancel(String reason)
    Cancel the intent that the pumpOp is part of.
     
    double
    Returns the effective rate for this operation.
    Return the id of the error handler.
    abstract long
    Returns the estimated time of the operation in ms.
    abstract double
    Returns the estimated volume of the operation in ml.
    com.tccc.kos.commons.util.concurrent.future.FutureWork
    Returns the future returned from buildFuture() .
    Return the list of grants required to perform this operation.
    Return all grants with the specified name.
    Returns the associated IngredientPipelineService , which is only available after bind() is called.
    Return the intent the pump op is part of.
    Pump<?>
    Returns the associated pump, which is only available after bind() is called.
    double
    Returns the rate of pour.
    Return the type of the pump op.
    boolean
    Returns whether dilution should be used during this operation.
    void
    setDiluted(boolean diluted)
    Sets whether dilution should be used during this operation.
    void
    setErrorHandlerId(String errorHandlerId)
    Set the name of the error handler.
    void
    setRate(double rate)
    Sets the rate of the pour.
    void
    start(com.tccc.kos.commons.util.concurrent.future.FutureWork future)
    Called when the future is started using a START callback on the future.
    void
    stop(com.tccc.kos.commons.util.concurrent.future.FutureWork future)
    Called when the future is completed using a COMPLETE callback on the future.
    void
    Called by the factory that creates the operation to validate that it is usable.

    Methods inherited from class java.lang.Object

    equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

  • Constructor Details

    • PumpOp

      public PumpOp()
  • Method Details

    • getType

      public String getType()
      Return the type of the pump op. This is useful for debugging.
    • getIngredientPipelineService

      public IngredientPipelineService getIngredientPipelineService()
      Returns the associated IngredientPipelineService , which is only available after bind() is called.
    • getPump

      public Pump<?> getPump()
      Returns the associated pump, which is only available after bind() is called.
    • getRate

      public double getRate()
      Returns the rate of pour. If zero, the nominal rate of the pump will be returned from getEffectiveRate() .
    • setRate

      public void setRate(double rate)
      Sets the rate of the pour.
    • getEffectiveRate

      public double getEffectiveRate()
      Returns the effective rate for this operation. If the rate is greater than zero, then the rate is returned, otherwise the nominal rate of the pump is returned. This can only be called after the operation has been bound to a pump.
    • isDiluted

      public boolean isDiluted()
      Returns whether dilution should be used during this operation.
    • setDiluted

      public void setDiluted(boolean diluted)
      Sets whether dilution should be used during this operation.
    • getErrorHandlerId

      public String getErrorHandlerId()
      Return the id of the error handler. Passed to IngredientPipelineErrorHandlerFactory to return an instance of the actual error handler to use while pouring.
    • setErrorHandlerId

      public void setErrorHandlerId(String errorHandlerId)
      Set the name of the error handler. Passed to IngredientPipelineErrorHandlerFactory to return an instance of the actual error handler to use while pouring.
    • getIntent

      public PumpIntent getIntent()
      Return the intent the pump op is part of.
    • addGrant

      public void addGrant(String grant)
      Add a grant to the list of required grants. This can be called from an operation constructor to define a grant that should be included in every instance of the operation. It is also called from XmlPumpIntentFactory to add any grants defined in the intent xml. If constructor grants should be ignored, specify inheritGrants="false" in the xml definition of the intent.
      Parameters:
      grant - the new limit to add
    • getGrants

      public Set<PumpOp.Grant> getGrants()
      Return the list of grants required to perform this operation.
    • getGrants

      public List<PumpOp.Grant> getGrants(String name)
      Return all grants with the specified name.
      Parameters:
      name - the name of the grants to return
    • getFuture

      public com.tccc.kos.commons.util.concurrent.future.FutureWork getFuture()
      Returns the future returned from buildFuture() . Useful for methods that aren't called with the future as a parameter.
    • validate

      public void validate() throws Exception
      Called by the factory that creates the operation to validate that it is usable. Operations are typically constructed as beans using setters, so populate the settings from a factory that is driven from a data file. This introduces the risk that the underlying data file is missing a required field. This method is called to ensure that operations are properly formed after they are loaded, by throwing an exception if the operation is poorly formed.
      Throws:
      Exception
    • start

      public void start(com.tccc.kos.commons.util.concurrent.future.FutureWork future)
      Called when the future is started using a START callback on the future. This allows any pre-future logic to be run, and allows this logic to be inherited so that it doesn't have to be baked into every subclass buildFuture() . This allows for cross-cutting functionality. Override as needed.
    • stop

      public void stop(com.tccc.kos.commons.util.concurrent.future.FutureWork future)
      Called when the future is completed using a COMPLETE callback on the future. This allows any post-future logic to run reliably without having to put the logic directly into buildFuture() . This allows for the functionality to be inherited by subclasses and allows for cross-cutting functionality. This is guaranteed to be called if start() is called. Override as needed.
    • getEstimatedTime

      public abstract long getEstimatedTime()
      Returns the estimated time of the operation in ms. This is used to compute the estimated time of one or more operations grouped together into a sequence. Ideally, this reflects the estimated time returned in the future from buildFuture() , so that estimates before an operation starts reflects the operation once it begins.

      In some cases the estimate may be more accurate when an operation actually starts, in which case the associated future may have a different value.

      If buildFuture() returns a future with an estimated time of zero, it will be overridden using the value of this method. This allows implementations of ops to ignore estimated time in buildFuture() as the framework will populate it automatically.

    • getEstimatedVolume

      public abstract double getEstimatedVolume()
      Returns the estimated volume of the operation in ml. This is used to compute the estimated volume of one or more operations grouped together into a sequence. This should only include the volume poured from the pump, not other pumps such as dilution. In cases where the volume is not easy to determine (runs until a sensor triggers), it is up to the developer to decide what value to return. This is generally used for informational purposes, such as showing the user an expected volume, such as for a calibration pour. This avoids the need to hard code values in the UI where they can get out of sync with the actual underlying intent.
    • buildFuture

      public abstract com.tccc.kos.commons.util.concurrent.future.FutureWork buildFuture(com.tccc.kos.commons.util.concurrent.future.FutureWork intentFuture)
      Returns a future which encapsulates the work that this operation must perform. The future is started by the caller, and it may be the case that all futures for a sequence are built before the sequence is started. This implies that a future should not be constructed differently based on external state that may change before the future is run. In this case, the future should check the external state when it is run, not when it is built.

      The returned future must be atomic under all conditions. That is, the operation must leave the system in a usable state whether it runs to completion successfully, is cancelled, or fails due to an error. An operation may generate a Trouble that results in future operations being non-runnable, but an operation may not leave internal hardware in a state that, when another valid operation is run, causes it to fail due to these internal state issues.

      The returned future can include an estimated time as this is used to compute the overall estimated time of a sequence of operations. If the actual time of an operation us unknown, use the following guidance:

      • If the operation may run longer due to an unexpected condition such as a lower flow rate than expected, simply use the expected time assuming nominal conditions.
      • If the operation may take a long time but typically ends much quicker, such as when trying to fill/empty a line, which may take minutes but probably takes seconds after already primed, use the longest expected time.
      In every case, when a future completes, the estimated time is automatically updated to reflect the actual time, and overall progress information is updated automatically to reflect this.

      If the future returned from this method does not include an estimated time (set to zero), then the framework overrides it using the result of getEstimatedTime() . This allows an operation to compute a more accurate estimated time when the future is constructed (when it knows the actual device and other details), but by default this method can simply ignore estimated time and let the framework fill it in.

      The future returned from this method is available via the getFuture() call.

      The intentFuture argument is the parent future for the entire intent. If the pump op changes state that must be cleaned up at the end of the intent, a callback on intentFuture can be used to ensure it is run when the intent is complete.

      Parameters:
      intentFuture - the parent future for the entire intent
    • cancel

      public void cancel(String reason)
      Cancel the intent that the pumpOp is part of.
      Specified by:
      cancel in interface com.tccc.kos.commons.util.Cancelable
    • abort

      public void abort(String reason)
      Abort the intent that the pumpOp is part of.
      Specified by:
      abort in interface com.tccc.kos.commons.util.Abortable
    • clone

      public Object clone() throws CloneNotSupportedException
      Throws:
      CloneNotSupportedException