// Medium.java package support; // protocol support package import java.util.Enumeration; // import Java enumerations import java.util.HashSet; // import Java hash sets import java.util.StringTokenizer; // import Java string tokenisers import java.util.Vector; // import Java vectors /** This is the class for a protocol medium. @author Iain A. Robin, Kenneth J. Turner @version 1.0 (1st September 1999, IAR): initial version

1.4 (9th March 2006, KJT): updated for JDK 1.5, use of Swing graphics, minor tidying
1.5 (27th July 2010, KJT): minor tidying; "isEmpty" check added */ public class Medium implements ProtocolEntity { /** Control delivery and loss */ public final static int CONTROL_DELIVERY_LOSS = 0; /** Control delivery (but not loss) */ public final static int CONTROL_DELIVERY = 1; /** Control neither delivery nor loss - immediately deliver on reception */ public final static int CONTROL_NOTHING = 2; /** PDUs in the medium */ protected Vector pdus; /** Destination events */ protected Vector destinationEvents; /** Medium control type */ private int mediumType = CONTROL_DELIVERY_LOSS; /** Constructor for a medium. */ public Medium() { initialise(); } /** Get the name attribute of a medium. @return The name value */ public String getName() { return("Medium"); } /** Identify and return PDU currently on the medium with type and parameters matching those in the given description. @param description service description @return corresponding PDU (or null if not found) */ protected PDU getMatchingPDU(String description) { PDU pdu; int seq = -1; // extract name of source entity for this PDU: int sourceStart = description.indexOf('[') + 1; int sourceEnd = description.indexOf(']'); String sourceName = description.substring(sourceStart, sourceEnd); // get type and parameters of PDU from action string // PDU type starts after first space following "Deliver" or "Lose" int typeStart = description.indexOf(' ') + 1; int typeEnd = description.indexOf('('); if (typeEnd < 0) typeEnd = sourceStart - 2; String type = description.substring(typeStart, typeEnd); String[] params = getParams(description); boolean noParams = params == null; int paramCount = noParams ? 0 : params.length; if (paramCount == 1) seq = Integer.parseInt(params[0]); // sequence number // try to match PDU type and seq with a PDU currently on channel for (Enumeration enumeration = pdus.elements(); enumeration.hasMoreElements(); ) { pdu = (PDU) enumeration.nextElement(); boolean matches = false; if (pdu != null && pdu.type.equals(type) && pdu.getSource().getName().equals(sourceName)) { if (noParams) matches = true; else if (seq >= 0) matches = pdu.seq == seq; } if (matches) return (pdu); } return (null); // no match found } /** Extract comma-separated parameter strings within round brackets in string argument. @param description description @return comma-separated parameters */ protected String[] getParams(String description) { int openBracket = description.indexOf("("); if (openBracket >= 0) { // check for opening bracket int closeBracket = description.indexOf(")"); String s1 = description.substring(openBracket + 1, closeBracket); StringTokenizer st = new StringTokenizer(s1, ","); String[] result = new String[st.countTokens()]; for (int i = 0; st.hasMoreTokens(); i++) result[i] = st.nextToken(); return (result); } return (null); } /** Return a list of strings describing actions (services) that can be carried out in the current state. @return service descriptions */ public Vector getServices() { Vector list = new Vector(); // initialise service list HashSet pdusSent = // initialise list of sources new HashSet(); for (Enumeration enumeration = pdus.elements(); // go through PDUs enumeration.hasMoreElements(); ) { PDU pdu = (PDU) enumeration.nextElement();// get next PDU if (pdu != null) { // non-null PDU? String name = pdu.getSource().getName();// get PDU source name String description = // get PDU id and name pdu.getID() + " [" + name + "]"; if (!pdusSent.contains(name)) { // no PDU with this source? pdusSent.add(name); // add source to list list.addElement( // add delivery service "Deliver " + description + " - no loss"); } if (mediumType == CONTROL_DELIVERY_LOSS)// delivery and loss controlled? list.addElement( // add loss service "Lose " + description + " - congestion/error"); } } return(list); // return service list } /** Initialise the medium. */ public void initialise() { pdus = new Vector(); destinationEvents = new Vector(); } /** Check if the medium is empty (i.e. has no PDUs in either direction). @return true/false if the medium has no/has PDUs */ public boolean isEmpty() { return(pdus == null || pdus.size() == 0); // return empty check } /** Check if the medium is empty (i.e. has no PDUs with the given source name). @param entityName entity name @return true/false if the medium has no/has PDUs */ public boolean isEmpty(String entityName) { for (Enumeration enumeration = pdus.elements(); // go through PDUs enumeration.hasMoreElements(); ) { PDU pdu = (PDU) enumeration.nextElement();// get next PDU String name = pdu.getSource().getName(); // get PDU source name if (name.equals(entityName)) // PDU with given source? return(false); // immediately return false } return(true); // return true as no PDUs } /** Carry out the action specified in the given string, and return a list of protocol events resulting from this action @param service service to perform @return resulting protocol events */ public Vector performService(String service) { Vector events = new Vector(); destinationEvents.removeAllElements(); PDU pdu = getMatchingPDU(service); if (pdu != null) { if (service.startsWith("Deliver")) { transmitPDU(pdu, pdu.getDestination()); pdus.removeElement(pdu); events.addElement(new ProtocolEvent(ProtocolEvent.RECEIVE, pdu)); } else if (service.startsWith("Lose")) { destinationEvents.removeAllElements(); pdus.removeElement(pdu); events.addElement(new ProtocolEvent(ProtocolEvent.LOSE, pdu)); } } // tack on any events triggered by delivery of a message // to its destination protocol entity for (Enumeration enumeration = destinationEvents.elements(); enumeration.hasMoreElements(); ) events.addElement((ProtocolEvent) enumeration.nextElement()); return(events); } /** Passively accept an incoming PDU and add to the list of those currently on channel. @param pdu PDU @return resulting protocol events */ public Vector receivePDU(PDU pdu) { Vector events = new Vector(); pdus.addElement(pdu); if (mediumType == CONTROL_NOTHING) { String s = "Deliver " + pdu.getID() + " [" + pdu.getSource().getName() + "] - no loss"; events.addAll(performService(s)); transmitPDU(pdu, pdu.getDestination()); } return(events); // return empty list of events } /** Set user control over delivery and loss. @param mediumType medium control type */ public void setMediumType(int mediumType) { this.mediumType = mediumType; } /** Deliver specified PDU to destination protocol entity, and get any protocol events triggered by this delivery. @param pdu PDU @param destination PDU destination */ public void transmitPDU(PDU pdu, ProtocolEntity destination) { destinationEvents = destination.receivePDU(pdu); } }