Class ServerQueue<T,QS extends QueueServer>

All Implemented Interfaces:
QueueStatus, NamedObjectOps
Direct Known Subclasses:
LinearServerQueue, PriorityServerQueue

public abstract class ServerQueue<T,QS extends QueueServer> extends DefaultSimObject implements QueueStatus
Queue with servers. This class provides support for creating queues with one or more servers. Instances of QueueServer represent the queue's servers, although typically a server will be a class that implements QueueServer (which is defined as an interface) so that the operations the server supports can be different for different queues. As long as servers are available (each server queue has a fixed number), new requests will be processed immediately, with requests queued when servers are not available. If the queue is not empty, the order in which entries are processed depends on the type of server queue being implemented.

A server queue can queue objects that implement QueueCallable or QueueRunnable, or are instances of TaskThread:

  • for the QueueCallable case, the user must provide two methods, interactWith(Server) and call(), where Server is a class implementing the QueueServer interface. The method interact with provides the code representing an interaction with a particular server, and when interactWith completes execution, the server is free to process other events. The method call() will then be executed and will handle any additional actions (e.g., scheduling additional events that would occur after a 'customer' finishes interacting with the server.
  • for the QueueRunnable case, the user must provide two methods, interactWith(Server) and run(), where Server is a class implementing the QueueServer interface. A TaskThread will be started, and this thread will first call interactWith. When interactWith returns, the server is free to process other events. The method run() will then be executed and the thread will terminate when run() returns.
  • for the TaskThread case, when a task thread is placed on a queue, an instance of the interface QueueServerHandler<Server> must be provided, where Server implements the QueueServer interface. QueueServerHandler provides a single method, interactWith(Server), and this method will be called when the task resumes execution and before the method suspending the task returns. When interactWith returns, the server is free to process other events.
When an event is scheduled, the processing time is the sum of the time provided when the event was queued and the value provided by the server, obtained by calling the getInterval() method declared by the QueueServer interface. This total represents the elapsed time needed to interact with a server and is the sum of the delays attributed to the server and to its 'customer'.

As long as the queue is not empty, entries will be pulled off the queue and processed whenever a server is available. If no servers are free, no entries in the queue are processed so that new entries merely accumulate.

The length of time for which a server is busy is the sum of the values of the server's getInterval() method and the server queue's task queue's getInterval(param) method, where the argument param is the value provided when the entry is added to the queue. This entry's type is T (one of the two type parameters) and its definition is provided by ServerQueue's subclasses. Objects of type T not only determine delay, but also provide any additional information needed for queuing (e.g., a priority level when the underlying task queue is a priority queue).

Otherwise, the behavior is similar to that of a task queue: when a Callable or a Runnable is added to a server queue, a SimulationEvent will be returned. If this event is null, that indicates that the attempt to add the Callable or Runnable to the queue failed (e.g., if the queue has a capacity limit). If this event is non-null, the operation succeeded. If the event is canceled (via the cancel method), the returned value will be true if the event could be canceled. The event can be canceled before is is scheduled and if it has not been canceled previously. If the event cannot be canceled, false will be returned.

When an existing task is added to a queue it will call a method such as addCurrentTask (subclasses of ServerQueue have methods with this name but with different signatures), which will block while the task is on the queue. The returned value will be true if the task successfully ran and false if the task was removed from the queue or could not be queued. If a variant of addCurrentTask that takes a SimEventCallable is used, the SimEventCallable's call method will be passed a Simulation event that can be canceled. The call to the event's cancel method will return true if the event was removed from the queue and false if the event was already scheduled or had already been canceled.

To implement a timeout for the Callable or Runnable case, code based on the following can be used:

    final SimulationEvent sev = taskQueue.add(new Callable() {
           public void call() {
              // operations when queuing was successful
           }
        }, PROCESSING_TIME);
        if (sev == null) {
           // case where the queuing request failed
        } else {
           simulation.scheduleCall(new Callable() {
               if (sev.cancel()) {
                // case where the timeout occurred
               }
           }, TIMEOUT);
        }
 
To implement a timeout for a task thread, code based on the following can be used:
    if (taskQueue.addCurrentTask(PROCESSING_TIME,
                                 new SimEventCallable() {
            public void call(final SimulationEvent sev) {
                 // store sev if it is necessary to tell if the
                 // timeout occurred, in which case sev.isCanceled()
                 // will return true.
                 simulation.scheduleCall(new Callable() {
                     sev.cancel();
                 }, TIMEOUT);
            }})) {
       // normal code
    } else {
       // code to run if there was a timeout or a failure to queue the
       // task.
    }
 
See Also:
  • Constructor Details

    • ServerQueue

      protected ServerQueue(Simulation sim, String name, boolean intern, TaskQueue<T> tq, QS... servers) throws IllegalArgumentException
      Constructor.
      Parameters:
      sim - the simulation
      name - the name of the queue
      intern - true if the queue name should be interned in the simulation tables; false otherwise
      tq - the TaskQueue used to store entries
      servers - the queue's servers
      Throws:
      IllegalArgumentException - typically means a name is already in use
  • Method Details

    • setDeletePolicy

      public void setDeletePolicy(QueueDeletePolicy policy)
      Set the deletion policy for this server queue's task queue.
      Parameters:
      policy - either TaskQueue.DeletePolicy.MUST_BE_EMPTY, TaskQueue.DeletePolicy.WHEN_EMPTY, TaskQueue.DeletePolicy.NEVER; WHEN_EMPTY is the default
    • getDeletePolicy

      public QueueDeletePolicy getDeletePolicy()
      Get the current deletion policy for the queue.
      Returns:
      the current deletion policy
    • canDelete

      public boolean canDelete()
      Determine if this named object can be deleted. A named object can be deleted if the method delete has not been called and if the object is not in a state that prevents the object from being deleted. Subclasses that override this method must call canDelete() for their superclasses and return false if the superclass' canDelete method returns false. The default method returns true if delete() has not been called and returned true.
      Specified by:
      canDelete in interface NamedObjectOps
      Returns:
      true if this object can be deleted; false otherwise
    • onDelete

      protected void onDelete()
      Complete the actions necessary to delete a named object. A subclass that overrides this method must call super.onDelete() at some point to complete the object deletion. This may not be within the onDelete method of the subclass if the deletion must be delayed for some reason (e.g., until some processing that is in progress has been completed). Once called, the object will be removed from the object-namer's tables and the object will be marked as deleted, so in general cleanup actions by a subclass should occur before it calls super.onDelete().
      Overrides:
      onDelete in class SimObject
    • addObserver

      public void addObserver(QueueObserver observer)
      Description copied from interface: QueueStatus
      Add an observer.
      Specified by:
      addObserver in interface QueueStatus
      Parameters:
      observer - the observer
    • removeObserver

      public void removeObserver(QueueObserver observer)
      Description copied from interface: QueueStatus
      Remove an observer.
      Specified by:
      removeObserver in interface QueueStatus
      Parameters:
      observer - the observer
    • getTaskQueue

      protected final TaskQueue<T> getTaskQueue()
      Get the TaskQueue associated with this server queue.
      Returns:
      the TaskQueue
    • setCanFreeze

      protected void setCanFreeze(boolean value)
      Set whether a queue can be frozen. Subclasses should call this method to change the default or to change whether or not the queue can be frozen. Normally it will called in a constructor, if at all.
      Parameters:
      value - true if the queue can be frozen; false if it cannot
    • canFreeze

      public boolean canFreeze()
      Determine if a queue can be frozen.
      Specified by:
      canFreeze in interface QueueStatus
      Returns:
      true if a queue can be frozen; false otherwise
      See Also:
    • freeze

      public void freeze(boolean value) throws UnsupportedOperationException
      Sets whether a queue is frozen or not. Freezing a queue means that all new entries go onto the queue rather than the first available being immediately scheduled. Subclasses must throw an UnsupportedOperationException if the queue cannot be frozen by the user.
      Parameters:
      value - true if the queue will be frozen; false if unfrozen
      Throws:
      UnsupportedOperationException - the queue can not be frozen
    • isFrozen

      public boolean isFrozen()
      Determine if a queue is frozen.
      Specified by:
      isFrozen in interface QueueStatus
      Returns:
      true if it is frozen; false otherwise
      See Also:
    • getIdleServer

      protected QS getIdleServer()
      Get a server. This places a server into use. When no more servers are available, the underlying task queue will stop processing entries until a server becomes available.
      Returns:
      the server
    • putIdleServer

      protected void putIdleServer(QS server)
      Release a server. This makes the server available for use and allow the underlying task queue to process entries.
      Parameters:
      server - the server
    • doAdd

      protected TaskQueueSimEvent<T> doAdd(QueueCallable<QS> callable, T parameters)
      Queue an event given a QueueCallable. This should be called by a subclass to add an event to a queue, as the currently scheduled event is handled specially. The subclass is responsible for using its "add" method's arguments to construct an instance of type T.
      Parameters:
      callable - the Callable specifying the task to be queued.
      parameters - the parameters used in queuing or scheduling the request
      Returns:
      the SimulationEvent created; null if the QueueCallable cannot be queued
    • doAdd

      protected TaskQueueSimEvent<T> doAdd(SimObjQueueCallable<QS> qcallable, T parameters)
      Queue an event given a SimObjQueueCallable. This should be called by a subclass to add an event to a queue, as the currently scheduled event is handled specially. The subclass is responsible for using its "add" method's arguments to construct an instance of type T.
      Parameters:
      qcallable - the Callable specifying the task to be queued.
      parameters - the parameters used in queuing or scheduling the request
      Returns:
      the SimulationEvent created; null if the QueueCallable cannot be queued
    • doAddCallObject

      protected TaskQueueSimEvent<T> doAddCallObject(Object scriptObject, T parameters) throws UnsupportedOperationException
      Queue an event given a script object that implements the QueueCallable interface. The script object must implement a method named interactWith that takes a QueueServer as its argument and a method with no arguments named call, which will be executed in that order in the simulation's thread. This should be called by a subclass to add an event to a queue, as the currently scheduled event is handled specially. The subclass is responsible for using its "add" method's arguments to construct an instance of type T. The method's first argument is an object defined in the simulation's scripting language that implements two methods: an interactWith method that takes a server as an argument (the server's type is set by the type parameter QS) and a call method that has no arguments. The interactWith method will be called first, followed by the call method.
      Parameters:
      scriptObject - the object specifying the task to be queued
      parameters - the parameters used in queuing or scheduling the request
      Returns:
      the SimulationEvent created; null if the QueueCallable cannot be queued
      Throws:
      UnsupportedOperationException
    • doAdd

      protected TaskQueueSimEvent<T> doAdd(QueueRunnable<QS> runnable, T parameters)
      Queue an event given a QueueRunnable. This should be called by a subclass to add an event to a queue, as the currently scheduled event is handled specially. The subclass is responsible for using its "add" method's arguments to construct an instance of type T.
      Parameters:
      runnable - the Runnable specifying the task to be queued.
      parameters - the parameters used in queuing or scheduling the request
      Returns:
      the SimulationEvent created; null if the QueueRunnable cannot be queued
    • doAdd

      protected TaskQueueSimEvent<T> doAdd(SimObjQueueRunnable<QS> qrunnable, T parameters)
      Queue an event given a SimObjQueueRunnable. This should be called by a subclass to add an event to a queue, as the currently scheduled event is handled specially. The subclass is responsible for using its "add" method's arguments to construct an instance of type T.
      Parameters:
      qrunnable - the Runnable specifying the task to be queued.
      parameters - the parameters used in queuing or scheduling the request
      Returns:
      the SimulationEvent created; null if the QueueRunnable cannot be queued
    • doAddTaskObject

      protected TaskQueueSimEvent<T> doAddTaskObject(Object scriptObject, T parameters) throws UnsupportedOperationException
      Queue an event given a script object that provides a QueueRunnable interface. The script object must implement a method named interactWith that takes a QueueServer as its argument and a method with no arguments named run, which will be executed in that order in a task thread. This should be called by a subclass to add an event to a queue, as the currently scheduled event is handled specially. The subclass is responsible for using its "add" method's arguments to construct an instance of type T.
      Parameters:
      scriptObject - the script object specifying the task to be queued.
      parameters - the parameters used in queuing or scheduling the request
      Returns:
      the SimulationEvent created; null if the QueueRunnable cannot be queued
      Throws:
      UnsupportedOperationException
    • addCurrentTaskScriptObject

      public boolean addCurrentTaskScriptObject(Object scriptObject, T param, Object scriptSimEventCallable) throws UnsupportedOperationException
      Add the currently running task thread to a queue, specifying a script object to implement the QueueServerHandler interface. The script object must implement a method named interactWith that takes a single argument, a QueueServer, and this method will be called before the task resumes. The scriptSimEventCallable argument is an object that implements a method named call that takes a single argument, a SimulationEvent. Typically this argument will be stored in case it is necessary to remove the task from the queue and restart it. This is public because the type parameter T may be a type for which autoboxing is possible. Otherwise it is usually more convenient for a subclass to implement a method that simply calls this method, with arguments providing data that will allow an object of type T to be constructed.
      Parameters:
      scriptObject - the script object specifying the interaction with a server
      param - the parameters used to determine how a queue insertion is done and how long to wait before the task is restarted once scheduled
      scriptSimEventCallable - the script object that obtains a SimulationEvent that can be used to remove the task from the queue
      Returns:
      true if the task was restarted by the queue; false if it was canceled or could not be queued
      Throws:
      UnsupportedOperationException
    • addCurrentTask

      public boolean addCurrentTask(QueueServerHandler<QS> handler, T param, SimEventCallable callable)
      Add the currently running task thread to a queue. This is public because the type parameter T may be a type for which autoboxing is possible. Otherwise it is usually more convenient for a subclass to implement a method that simply calls this method, with arguments providing data that will allow an object of type T to be constructed in addition the the SimEventCallable argument.
      Parameters:
      handler - this argument's interactWith method will be called with a server as its argument when the event is scheduled; may be null if the interactWith method would simply return without performing any operations.
      param - the parameters used to determine how a queue insertion is done and how long to wait before the task is restarted once scheduled
      callable - this argument's call method will be run when the event is scheduled and will be passed a simulation event (e.g., to store the event to allow the event to be canceled)
      Returns:
      true on success; false on failure in which case the current thread will continue to run
    • size

      public int size()
      Get the size of the queue. The size does not include the currently scheduled event.
      Specified by:
      size in interface QueueStatus
      Returns:
      the queue size
    • isBusy

      public boolean isBusy()
      Determine if the queue is busy. A queue is busy if all the servers are handling queue entries.
      Specified by:
      isBusy in interface QueueStatus
      Returns:
      true if the queue is busy; false otherwise
    • inUseCount

      public int inUseCount()
      Determine how many servers are in use.
      Specified by:
      inUseCount in interface QueueStatus
      Returns:
      the number of servers in use
    • serverCount

      public int serverCount()
      Determine the maximum number of servers.
      Specified by:
      serverCount in interface QueueStatus
      Returns:
      the maximum number of servers
    • printConfiguration

      public void printConfiguration(String iPrefix, String prefix, boolean printName, PrintWriter out)
      Print this simulation object's configuration. Documentation for the use of this method is provided by the documentation for the SimObject method SimObject.printConfiguration(String,String,boolean,PrintWriter).

      When the third argument has a value of true, the object name and class name will be printed in a standard format with its indentation provided by the iPrefix argument. In addition, the configuration that is printed includes the following.

      Defined in ServerQueue:

      • the number of servers.
      • the deletion policy.
      • the value of the can freeze flag.
      • the value of the concurrency limit.
      Overrides:
      printConfiguration in class DefaultSimObject
      Parameters:
      iPrefix - the prefix to use for an initial line when printName is true with null treated as an empty string
      prefix - a prefix string (typically whitespace) to put at the start of each line other than the initial line that is printed when printName is true
      printName - requests printing the name of an object
      out - the output print writer
    • printState

      public void printState(String iPrefix, String prefix, boolean printName, PrintWriter out)
      Print this simulation object's state. Documentation for the use of this method is provided by the documentation for the SimObject method SimObject.printState(String,String,boolean,PrintWriter).

      When the second argument has a value of true, the object name and class name will be printed in a standard format with its indentation provided by the iPrefix argument. In addition, the state that is printed includes the following.

      Defined in ServerQueue:

      • the queue size.
      • whether or the queue is frozen.
      • whether or not the queue is busy.
      • the number of 'customers' being serviced.
      Overrides:
      printState in class DefaultSimObject
      Parameters:
      iPrefix - the prefix to use for an initial line when printName is true with null treated as an empty string
      prefix - a prefix string (typically whitespace) to put at the start of each line other than the initial line that is printed when printName is true
      printName - requests printing the name of an object
      out - the output print writer
    • clone

      protected Object clone() throws CloneNotSupportedException
      Creates and returns a copy of this object. This method will throw the exception CloneNotSupportedException if the object is interned.
      Overrides:
      clone in class Object
      Throws:
      CloneNotSupportedException - a clone could not be created
      See Also:
    • isInterned

      public boolean isInterned()
      Determine if an object is interned in a object namer's tables.
      Specified by:
      isInterned in interface NamedObjectOps
      Returns:
      true if the object is interned; false if not
    • getObjectNamer

      protected Simulation getObjectNamer()
      Get the object namer for a named object.
      Returns:
      the object namer for this named object
    • getName

      public final String getName()
      Get an object's name.
      Specified by:
      getName in interface NamedObjectOps
      Returns:
      the name of the object
    • delete

      public final boolean delete()
      Delete an object. An object can only be deleted once. If this method returns true, the object (if interned) will have been removed from the object namer tables.

      The implementations provided by DefaultNamedObect and generated because of a @NamedObject annotation provide a protected method named onDelete. A subclass that overrides onDelete() must call the onDelete method of its superclass after it's onDelete method has been called and any cleanup actions performed. In some cases, this may happen at a later time (e.g., if a thread is used for some of the cleanup operations or if it is otherwise necessary to wait).

      Specified by:
      delete in interface NamedObjectOps
      Returns:
      true if the deletion request was accepted; false otherwise
    • isDeleted

      public final boolean isDeleted()
      Determine if an object has been deleted. An object is deleted if the method delete() has been called and returned true.
      Specified by:
      isDeleted in interface NamedObjectOps
      Returns:
      true if deleted; false otherwise
    • deletePending

      public final boolean deletePending()
      Determine if an object is being deleted. An deletion is pending if the method delete() has been called and returned true but the deletion has not been completed.
      Specified by:
      deletePending in interface NamedObjectOps
      Returns:
      true if deletion is pending; false otherwise