You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
259 lines
8.2 KiB
Java
259 lines
8.2 KiB
Java
4 years ago
|
// 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 <br/>
|
||
|
<br/> 1.4 (9th March 2006, KJT): updated for JDK 1.5, use of Swing
|
||
|
graphics, minor tidying
|
||
|
<br/> 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<PDU> pdus;
|
||
|
|
||
|
/** Destination events */
|
||
|
protected Vector<ProtocolEvent> 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<String> getServices() {
|
||
|
Vector<String> list = new Vector<String>(); // initialise service list
|
||
|
HashSet<String> pdusSent = // initialise list of sources
|
||
|
new HashSet<String>();
|
||
|
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<PDU>();
|
||
|
destinationEvents = new Vector<ProtocolEvent>();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
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<ProtocolEvent> performService(String service) {
|
||
|
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
|
||
|
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<ProtocolEvent> receivePDU(PDU pdu) {
|
||
|
Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|