// MCASTRouterA.java package protocol; // protocol package import java.util.*; // import Java utility classes import support.*; // import Jasper support classes /** This is the class that supports a router for broad/uni/multicast. @author Kenneth J. Turner @version 1.0 (22nd July 2010, KJT): initial version */ public class MCASTRouter implements ProtocolEntity { /** Service send offer */ private final static String SEND = "Forward message for router "; /** Current router letter */ public char currentRouter; /** Service provider events */ private Vector serviceEvents; /** Service data unit output */ private Vector sdus; /** Service entity name */ private String serviceName; /** Constructor for sources/sinks. @param serviceName service name */ public MCASTRouter(String serviceName) { this.serviceName = serviceName; // set service name currentRouter = lastOf(serviceName); // set current router letter initialise(); // initialise service entity } /** Find the SDU with the given destinations. @param destinations destinations @return the corresponding SDU (or null if none) */ public MCASTSdu findSDU(String destinations) { MCASTSdu result = null; // initialise SDU result for (int i = 0; i < sdus.size(); i++) { // go through SDUs MCASTSdu sdu = sdus.get(i); // get SDU if (sdu.destinations.equals(destinations)) { // destinations found? result = sdu; // save result break; // exit loop } } return(result); // return SDU } /** Get first character of string. @param string string to extract from @return first character of string */ public char firstOf(String string) { char letter = '?'; // initialise letter if (string != null) { // non-null string? int length = string.length(); // get string length if (length > 0) // non-empty string? letter = string.charAt(0); // get first character } return(letter); // return first character } /** Return the service name. @return service name */ public String getName() { return(serviceName); // return service name } /** Return the service data units. @return service data units */ public Vector getSDUs() { return(sdus); // return service data units } /** Return services currently offered. @return list of services */ public Vector getServices() { Vector list = new Vector(); // initialise service list if (sdus != null && sdus.size() > 0) { // SDUs from service user? for (int i = 0; i < sdus.size(); i++) { // go through SDUs MCASTSdu sdu = sdus.get(i); // get SDU String destinations = sdu.destinations; // get SDU destinations String destination = ""; // initialise destination for (int j = 0; j < destinations.length(); j++) { // go through dests. if (j > 0) // not first destination? destination += ", "; // append comma destination += destinations.charAt(j);// append destination } char router = firstOf(destination); // get router letter if (router != currentRouter) // not current router? list.addElement(SEND + destination); // add send to list } } return(list); // return service list } /** Initialise the service entity. */ public void initialise() { serviceEvents = new Vector();// initialise service events sdus = new Vector(); // initialise SDUs } /** Get last character of string. @param string string to extract from @return last character of string */ public char lastOf(String string) { char letter = '?'; // initialise letter if (string != null) { // non-null string? int length = string.length(); // get string length if (length > 0) // non-empty string? letter = string.charAt(length - 1); // get last character } return(letter); // return last character } /** Check if the destination router is more than one hop from the current router (i.e. is not the next router letter. @param destination entity destination @return true/false if destination is not/is adjacent */ public boolean laterRouter(ProtocolEntity destination) { int currentIndex = (int) currentRouter; // get current router index int destinationIndex = // get destination router index (int) ((MCASTRouter) destination).currentRouter; return(destinationIndex > currentIndex + 1);// return router letter check } /** Return the next router to reach the destination. This is a very restricted routing table for the purposes of this example. @param destination entity destination @return next entity destination */ public ProtocolEntity nextRouter(ProtocolEntity destination) { char destinationLetter = // get destination router letter ((MCASTRouter) destination).currentRouter; char nextLetter = destinationLetter; // assume destination by default switch (currentRouter) { // route based on current router case 'A': // at router A? switch (destinationLetter) { // check destination index case 'D': // to router D? nextLetter = 'C'; // via C break; case 'E': // to router E? nextLetter = 'C'; // via C break; } break; } return(MCAST.getEntity(nextLetter)); // return next router entity } /** Perform service. Note that the current implementation works for a particular topology but is not general. When there are multiple destinations, the router forward to the first two of these. A more general implementation would embody particular knowledge about routing. @param service service request @return resulting service events */ public Vector performService(String service) { serviceEvents = new Vector();// initialise service events if (service.startsWith(SEND)) { // send request? String destinations = // get destinations service.substring(SEND.length()); String destination = // remove destination commas destinations.replaceAll(", ", ""); // get destination(s) MCASTSdu sdu = findSDU(destination); // find corresponding SDU char router = firstOf(destination); // get destination router letter serviceEvents.addElement( // add forward comment MCAST.comment(this, "forward")); transmitPDU(sdu, router); // transmit SDU sdus.remove(sdu); // remove SDU from SDUs } return(serviceEvents); // return service events } /** Receive an SDU. @param sdu SDU @return resulting service events */ public Vector receivePDU(PDU sdu) { serviceEvents = new Vector();// initialise service events if (sdu != null) { // non-empty SDU? String destinations = // get SDU destination(s) ((MCASTSdu) sdu).destinations; if (destinations.length() > 1) { // more than one destination? String message = ((MCASTSdu) sdu).sdu; // get SDU message sdu = // get SDU for first destination new MCASTSdu(destinations.substring(0, 1), message); sdus.addElement((MCASTSdu) sdu); // store SDU sdu = // get SDU for later dests. new MCASTSdu(destinations.substring(1), message); sdus.addElement((MCASTSdu) sdu); // store SDU } else // one destination sdus.addElement((MCASTSdu) sdu); // store SDU } return(serviceEvents); // return service events } /** Send an SDU to the given destination letter. @param sdu SDU @param destination destination letter */ public void transmitPDU(PDU sdu, char destination) { ProtocolEntity entityDestination = // get protocol entity dest. MCAST.getEntity(destination); transmitPDU(sdu, entityDestination); // transmit PDU } /** Send an SDU to the given destination entity. @param sdu SDU @param destination destination entity */ public void transmitPDU(PDU sdu, ProtocolEntity destination) { destination = nextRouter(destination); // set next router destination sdu.setSource(this); // set source as this entity sdu.setDestination(destination); // set destination serviceEvents.addElement( // add send event new ProtocolEvent(ProtocolEvent.SEND, sdu)); Vector receiveEvents = // receive SDU at destination destination.receivePDU(sdu); if (laterRouter(destination)) { // later router? serviceEvents.addElement( // add send event new ProtocolEvent(ProtocolEvent.TRAVERSE, sdu)); } for (int i = 0; i < receiveEvents.size(); i++) // go through receive events serviceEvents.addElement( // append receive event receiveEvents.get(i)); } }