Seize.java
package nl.tudelft.simulation.dsol.formalisms.flow;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.djutils.event.EventType;
import org.djutils.metadata.MetaData;
import org.djutils.metadata.ObjectDescriptor;
import nl.tudelft.simulation.dsol.formalisms.Resource;
import nl.tudelft.simulation.dsol.formalisms.ResourceRequestorInterface;
import nl.tudelft.simulation.dsol.simtime.SimTime;
import nl.tudelft.simulation.dsol.simulators.DevsSimulatorInterface;
/**
* The Seize flow block requests a resource and keeps the entity within the flow block's queue until the resource is actually
* claimed. Note that the Seize block has a queue in which the Entity is waiting, while the Resource has a queue in which the
* request is waiting. This sounds like we store the same information twice. This is, however, not the case. (1) Multiple Seize
* blocks can share the same Resource, each holding their own entities that make the request, where the total set of requests is
* stored at the Resource. (2) A Seize could potentially request access to two resources, where the entity is held at the Seize
* block until both are available. Each Resource keeps and grants its own requests. Since there nam be an n:m relationship
* between Seize blocks and Resources, each have their own queue, with its own sorting mechanism (ideally the same).
* <p>
* Copyright (c) 2002-2024 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
* for project information <a href="https://simulation.tudelft.nl/" target="_blank"> https://simulation.tudelft.nl</a>. The DSOL
* project is distributed under a three-clause BSD-style license, which can be found at
* <a href="https://https://simulation.tudelft.nl/dsol/docs/latest/license.html" target="_blank">
* https://https://simulation.tudelft.nl/dsol/docs/latest/license.html</a>.
* </p>
* @author <a href="https://www.linkedin.com/in/peterhmjacobs">Peter Jacobs </a>
* @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
* @param <T> the time type
*/
public class Seize<T extends Number & Comparable<T>> extends FlowObject<T> implements ResourceRequestorInterface<T>
{
/** */
private static final long serialVersionUID = 20140911L;
/** QUEUE_LENGTH_EVENT is fired when the queue length is changed. */
public static final EventType QUEUE_LENGTH_EVENT = new EventType(new MetaData("QUEUE_LENGTH_EVENT", "Queue length",
new ObjectDescriptor("queueLength", "Queue length", Integer.class)));
/** DELAY_TIME is fired when a new delayTime is computed. */
public static final EventType DELAY_TIME = new EventType(new MetaData("DELAY_TIME", "Delay time",
new ObjectDescriptor("delayTime", "Delay time (as a double)", Double.class)));
/** queue refers to the list of waiting requestors. */
private List<Request<T>> queue = Collections.synchronizedList(new ArrayList<Request<T>>());
/** requestedCapacity is the amount of resource requested on the resource. */
private double requestedCapacity = Double.NaN;
/** resource on which the capacity is requested. */
private Resource<T> resource;
/**
* Constructor for Seize flow object.
* @param id String; the id of the FlowObject
* @param simulator DevsSimulatorInterface<T>; on which behavior is scheduled
* @param resource Resource<T>; which is claimed
*/
public Seize(final String id, final DevsSimulatorInterface<T> simulator, final Resource<T> resource)
{
this(id, simulator, resource, 1.0);
}
/**
* Constructor for Seize flow object.
* @param id String; the id of the FlowObject
* @param simulator DevsSimulatorInterface<T>; on which behavior is scheduled
* @param resource Resource<T>; which is claimed
* @param requestedCapacity double; is the amount which is claimed by the seize
*/
public Seize(final String id, final DevsSimulatorInterface<T> simulator, final Resource<T> resource,
final double requestedCapacity)
{
super(id, simulator);
if (requestedCapacity < 0.0)
{
throw new IllegalArgumentException("requestedCapacity cannot < 0.0");
}
this.requestedCapacity = requestedCapacity;
this.resource = resource;
}
/**
* Receive an object that requests an amount of units from a resource.
* @param entity Entity<T>; the object
* @param pRequestedCapacity double; the requested capacity
*/
public synchronized void receiveObject(final Entity<T> entity, final double pRequestedCapacity)
{
super.receiveEntity(entity);
Request<T> request = new Request<T>(entity, pRequestedCapacity, getSimulator().getSimulatorTime());
synchronized (this.queue)
{
this.queue.add(request);
}
try
{
this.fireTimedEvent(Seize.QUEUE_LENGTH_EVENT, this.queue.size(), getSimulator().getSimulatorTime());
this.resource.requestCapacity(pRequestedCapacity, this);
}
catch (Exception exception)
{
getSimulator().getLogger().always().warn(exception, "receiveObject");
}
}
/** {@inheritDoc} */
@Override
public void receiveEntity(final Entity<T> entity)
{
this.receiveObject(entity, this.requestedCapacity);
}
/**
* sets the queue to this seize. This enables seize blocks to share one queue.
* @param queue List<Request<T>>; is a new queue.
*/
public void setQueue(final List<Request<T>> queue)
{
this.queue = queue;
}
/**
* Return the queue.
* @return List<Request<T>>; the queue with requests to claim the resource
*/
public List<Request<T>> getQueue()
{
return this.queue;
}
/** {@inheritDoc} */
@Override
public void receiveRequestedResource(final double pRequestedCapacity, final Resource<T> pResource)
{
for (Request<T> request : this.queue)
{
if (request.getAmount() == pRequestedCapacity)
{
synchronized (this.queue)
{
this.queue.remove(request);
}
this.fireTimedEvent(Seize.QUEUE_LENGTH_EVENT, this.queue.size(), getSimulator().getSimulatorTime());
T delay = SimTime.minus(getSimulator().getSimulatorTime(), request.getQueueEntryTime());
this.fireTimedEvent(Seize.DELAY_TIME, delay.doubleValue(), getSimulator().getSimulatorTime());
this.releaseEntity(request.getEntity());
return;
}
}
}
/**
* The Request Class defines the requests for resource.
* @param <T> the time type
*/
public static class Request<T extends Number & Comparable<T>>
{
/** amount is the requested amount. */
private final double amount;
/** entity is the object requesting the amount. */
private final Entity<T> entity;
/** the time when the request was created. */
private final T queueEntryTime;
/**
* Method Request.
* @param entity Entity<T>; the requesting entity
* @param amount double; is the requested amount
* @param queueEntryTime T; the time the request was created
*/
public Request(final Entity<T> entity, final double amount, final T queueEntryTime)
{
this.entity = entity;
this.amount = amount;
this.queueEntryTime = queueEntryTime;
}
/**
* Return the requested amount.
* @return double; the requested amount
*/
public double getAmount()
{
return this.amount;
}
/**
* Return the entity.
* @return Entity<T>; the entity
*/
public Entity<T> getEntity()
{
return this.entity;
}
/**
* Returns the time when the request was made.
* @return T; the time when the request was made
*/
public T getQueueEntryTime()
{
return this.queueEntryTime;
}
}
}