package nl.tudelft.simulation.examples.dsol.terminal; import java.rmi.RemoteException; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.SortedSet; import java.util.TreeSet; import java.util.concurrent.atomic.AtomicLong; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import nl.tudelft.simulation.dsol.SimRuntimeException; import nl.tudelft.simulation.dsol.simtime.SimTime; import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface; import nl.tudelft.simulation.event.EventProducer; import nl.tudelft.simulation.event.EventType; /** * A resource defines a shared and limited amount. *

* (c) 2002-2018 Delft University of Technology , the * Netherlands.
* See for project information www.simulation.tudelft.nl
* License of use: Lesser General Public License (LGPL) , no * warranty. * @author Alexander Verbraeck * @version $Revision: 1.2 $ $Date: 2010/08/10 11:36:45 $ * @param the absolute time type to use in timed events * @param the relative time type * @param the simulation time type to use. * @since 1.5 */ public class IntResource, R extends Number & Comparable, T extends SimTime> extends EventProducer { /** */ private static final long serialVersionUID = 20140805L; /** the counter counting the requests. package visibility, so Request can access it. */ @SuppressWarnings("checkstyle:visibilitymodifier") static AtomicLong counter = new AtomicLong(0); // XXX: OUCH /** UTILIZATION_EVENT is fired on activity. */ public static final EventType UTILIZATION_EVENT = new EventType("UTILIZATION_EVENT"); /** RESOURCE_REQUESTED_QUEUE_LENGTH fired on changes in queue length. */ public static final EventType RESOURCE_REQUESTED_QUEUE_LENGTH = new EventType("RESOURCE_REQUESTED_QUEUE_LENGTH"); /** the minimum priority. */ public static final int MIN_REQUEST_PRIORITY = 0; /** the maximum priority. */ public static final int MAX_REQUEST_PRIORITY = 10; /** the default average priority. */ public static final int DEFAULT_REQUEST_PRIORITY = 5; /** capacity defines the maximum capacity of the resource. */ private long capacity; /** claimedCapacity defines the currently claimed capacity. */ protected long claimedCapacity = 0; /** request defines the list of requestors for this resource. */ protected SortedSet> requests = Collections.synchronizedSortedSet(new TreeSet>(new RequestComparator())); /** simulator defines the simulator on which is scheduled. */ protected DEVSSimulatorInterface simulator; /** the description of the resource. */ protected String description = "resource"; /** the logger. */ private static Logger logger = LogManager.getLogger(IntResource.class); /** * Method Resource. * @param simulator on which is scheduled * @param description the description of this resource * @param capacity of the resource */ public IntResource(final DEVSSimulatorInterface simulator, final String description, final long capacity) { super(); this.description = description; this.simulator = simulator; this.capacity = capacity; } /** * Method Resource. * @param simulator on which is scheduled * @param capacity of the resource */ public IntResource(final DEVSSimulatorInterface simulator, final long capacity) { this(simulator, "resource", capacity); } /** * returns the maximum, and thus original capacity of the resource. * @return capacity the maximum, and thus original capacity of the resource. */ public final long getCapacity() { return this.capacity; } /** * returns the amount of currently claimed capacity. * @return the amount of currently claimed capacity. */ public final long getClaimedCapacity() { return this.claimedCapacity; } /** * returns the currently available capacity on this resource. This method is implemented as * return this.getCapacity()-this.getClaimedCapacity() * @return the currently available capacity on this resource. */ public final long getAvailableCapacity() { return this.capacity - this.claimedCapacity; } /** * returns the number of instances currently waiting for this resource. * @return the number of instances currently waiting for this resource */ public final int getQueueLength() { return this.requests.size(); } /** * Method alterClaimedCapacity. * @param amount refers the amount which is added to the claimed capacity * @throws RemoteException on network failure */ private synchronized void alterClaimedCapacity(final long amount) throws RemoteException { this.claimedCapacity += amount; this.fireTimedEvent(IntResource.UTILIZATION_EVENT, this.claimedCapacity, this.simulator.getSimulatorTime()); } /** * sets the capacity of the resource. * @param capacity the new maximal capacity */ public final void setCapacity(final long capacity) { this.capacity = capacity; try { this.releaseCapacity(0); } catch (RemoteException remoteException) { // This exception cannot occur. logger.warn("setCapacity", remoteException); } } /** * requests an amount of capacity from the resource. * @param amount the requested amount * @param requestor the RequestorInterface requesting the amount * @throws RemoteException on network failure * @throws SimRuntimeException on other failures */ public final synchronized void requestCapacity(final long amount, final IntResourceRequestorInterface requestor) throws RemoteException, SimRuntimeException { this.requestCapacity(amount, requestor, IntResource.DEFAULT_REQUEST_PRIORITY); } /** * requests an amount of capacity from the resource. * @param amount the requested amount * @param requestor the RequestorInterface requesting the amount * @param priority the priority of the request * @throws RemoteException on network failure * @throws SimRuntimeException on other failures */ public final synchronized void requestCapacity(final long amount, final IntResourceRequestorInterface requestor, final int priority) throws RemoteException, SimRuntimeException { if (amount < 0) { throw new SimRuntimeException("requested capacity on resource cannot < 0.0"); } if ((this.claimedCapacity + amount) <= this.capacity) { this.alterClaimedCapacity(amount); this.simulator.scheduleEventNow(this, requestor, "receiveRequestedResource", new Object[]{new Long(amount), this}); } else { synchronized (this.requests) { this.requests.add(new Request(requestor, amount, priority)); } this.fireTimedEvent(IntResource.RESOURCE_REQUESTED_QUEUE_LENGTH, (double) this.requests.size(), this.simulator.getSimulatorTime()); } } /** * releases an amount of capacity from the resource. * @param amount the amount to release * @throws RemoteException on network failure */ public final void releaseCapacity(final long amount) throws RemoteException { if (amount < 0) { throw new IllegalArgumentException("released capacity on resource cannot < 0.0"); } if (amount > 0) { this.alterClaimedCapacity(-Math.min(this.capacity, amount)); } synchronized (this.requests) { for (Iterator> i = this.requests.iterator(); i.hasNext();) { Request request = i.next(); if ((this.capacity - this.claimedCapacity) >= request.getAmount()) { this.alterClaimedCapacity(request.getAmount()); request.getRequestor().receiveRequestedResource(request.getAmount(), this); synchronized (this.requests) { i.remove(); } this.fireTimedEvent(IntResource.RESOURCE_REQUESTED_QUEUE_LENGTH, (double) this.requests.size(), this.simulator.getSimulatorTime()); } else { return; } } } } /** {@inheritDoc} */ @Override public String toString() { return this.description; } /** * the RequestComparator. This comparator first checks on priority, then on ID. */ protected class RequestComparator implements Comparator> { /** {@inheritDoc} */ @Override public final int compare(final Request arg0, final Request arg1) { if (arg0.getPriority() > arg1.getPriority()) { return -1; } if (arg0.getPriority() < arg1.getPriority()) { return 1; } if (arg0.getId() < arg1.getId()) { return -1; } if (arg0.getId() > arg1.getId()) { return 1; } return 0; } } /** * A Request. * @param the absolute time type to use in timed events * @param the relative time type * @param the simulation time type to use. */ public static class Request, R extends Number & Comparable, T extends SimTime> { /** the priority of the request. */ private int priority = 5; /** the number of this request. */ private long id = -1; /** requestor the resourceRequestor. */ private IntResourceRequestorInterface requestor; /** amount is the amount requested by the resource. */ private long amount; /** * constructs a new Request. * @param requestor the requestor * @param amount the requested amount * @param priority the priority of the request */ public Request(final IntResourceRequestorInterface requestor, final long amount, final int priority) { this.requestor = requestor; this.amount = amount; this.priority = priority; this.id = IntResource.counter.incrementAndGet(); } /** * gets the requested amount. * @return the requested amount */ public final long getAmount() { return this.amount; } /** * gets the requestor. * @return the Requestor. */ public final IntResourceRequestorInterface getRequestor() { return this.requestor; } /** * returns the priority of the request. * @return the priority */ public final int getPriority() { return this.priority; } /** * returns the id of the request. * @return the id */ public final long getId() { return this.id; } /** {@inheritDoc} */ @Override public final String toString() { return "RequestForResource[requestor=" + this.requestor + ";amount=" + this.amount + ";priority=" + this.priority + "]"; } } }