/* Copyright (C) 2004 [Jörg Rüdenauer] This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package tokenring; import fdda.algorithm.Node; import fdda.algorithm.Message; import fdda.algorithm.WrongStateException; import fdda.model.Property; import fdda.model.PropertyFactory; import fdda.model.PropertyAdapter; import fdda.model.PropertyEvent; import fdda.model.PropertyHolder; import java.awt.Color; import java.util.Random; /** * Demonstrates the token ring leader election with message extinction. */ public class RingElection extends TokenRingNode { /** Random instance used by all instances */ private static Random random = new Random(System.currentTimeMillis()); /** the ID of the node */ private int ID; /** the highest ID known so far */ private int highestID; /** has the node already sent a message with its own ID or a higher ID */ private boolean messageSent = false; /* * (non-Javadoc) * @see fdda.algorithm.Node#initialize() */ public void initialize() { // get the model node fdda.model.Node modelNode = this.getModelNode(); // add a property for the IDs Property idProperty = PropertyFactory.createProperty("RingID", "Integer", "ID", "The ID of the node. The node with the highest ID gets elected."); idProperty.setModifiable(true); // the user can change it idProperty.setVisible(true); // therefore, he must see it // no change must be possible once the algorithm is started idProperty.setFacet(Property.FIXED_WHILE_RUNNING, Boolean.TRUE); idProperty.setFacet(Property.DEFAULT_VALUE, new Integer(1)); idProperty.setFacet(Property.MAX_VALUE, new Integer(9999)); idProperty.setFacet(Property.MIN_VALUE, new Integer(1)); idProperty.addValue(new Integer(1)); modelNode.addProperty(idProperty); // add a property showing the known highest ID Property highestIDProperty = PropertyFactory.createProperty("highestID", "Integer", "Highest ID", "The highest known ID to the node."); highestIDProperty.setModifiable(false); highestIDProperty.setVisible(true); highestIDProperty.addValue(new Integer(1)); modelNode.addProperty(highestIDProperty); highestID = 1; ID = 1; // link the ID to the label modelNode.addPropertyListener(new PropertyAdapter() { public void propertyChanged(PropertyEvent e) { if (e.getProperty().getName().equals("RingID")) { ID = ((Integer)e.getProperty().getValue()).intValue(); Property labelProperty = ((PropertyHolder)e.getSource()). getProperty(fdda.model.Node.LABEL_PROPERTY_NAME); labelProperty.setValueAt(0, "" + ID); // update highest known ID field if (ID > highestID) { highestID = ID; Property highestIDProperty = ((PropertyHolder)e.getSource()). getProperty("highestID"); highestIDProperty.setValueAt(0, new Integer(ID)); } } } // propertyAdded is called while the node is parsed from the file public void propertyAdded(PropertyEvent e) { if (e.getProperty().getName().equals("RingID")) { ID = ((Integer)e.getProperty().getValue()).intValue(); Property labelProperty = ((PropertyHolder)e.getSource()). getProperty(fdda.model.Node.LABEL_PROPERTY_NAME); labelProperty.setValueAt(0, "" + ID); // update highest known ID field if (ID > highestID) { highestID = ID; Property highestIDProperty = ((PropertyHolder)e.getSource()). getProperty("highestID"); highestIDProperty.setValueAt(0, new Integer(ID)); } } } }); // the label shall not be modified by the user directly (linked to ID) Property labelProperty = modelNode.getProperty(fdda.model.Node.LABEL_PROPERTY_NAME); labelProperty.setModifiable(false); labelProperty.setValueAt(0, "" + ID); // set node to be active modelNode.getProperty(fdda.model.Node.ACTIVE_PROPERTY_NAME). setValueAt(0, Boolean.TRUE); } /* * (non-Javadoc) * @see fdda.algorithm.Node#prepareForStart() */ public void prepareForStart() { // maybe the algorithm was called once already. Revert node color. this.setPrimaryColor(Color.WHITE); highestID = ID; getModelNode().getProperty("highestID").setValueAt(0, new Integer(highestID)); messageSent = false; } /* * (non-Javadoc) * @see fdda.algorithm.Node#start() */ public void start() throws WrongStateException { // we wait a random time between 1/2 and 4 seconds for the real start int time = random.nextInt(3500); time += 500; this.sleepTime(time); } /* * (non-Javadoc) * @see fdda.algorithm.Node#run() */ public void run() throws WrongStateException { // send a message with the own ID to the next node if (!messageSent) { this.sendMessageToNextNode(new Integer(highestID), "" + highestID); messageSent = true; } // go to sleep this.sleep(); } /* * (non-Javadoc) * @see fdda.algorithm.Node#messageReceived(fdda.algorithm.Node, fdda.algorithm.Message) */ public void messageReceived(Node sender, Message message) throws WrongStateException { int messageID = ((Integer)message.getPayload()).intValue(); // check whether the message transports a new, higher ID if (highestID < messageID) { highestID = messageID; getModelNode().getProperty("highestID").setValueAt(0, new Integer(highestID)); // send message with own ID onwards this.sendMessageToNextNode(new Integer(highestID), "" + highestID); messageSent = true; } else if (highestID > messageID) { // message extinction if (!messageSent) { this.sendMessageToNextNode(new Integer(highestID), "" + highestID); messageSent = true; } } if (messageID == ID) { // I am the elected node this.setPrimaryColor(Color.GREEN); } } }