/** * Fortika - Robust Group Communication * Copyright (C) 2002-2006 Sergio Mena de la Cruz (EPFL) (sergio.mena@epfl.ch) * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package framework; import java.io.BufferedReader; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.text.MessageFormat; import java.text.ParsePosition; import uka.transport.Transportable; /** * This class represents the identity of a process. It is used whenever a process wants to * refer to anther process inside any of the protocols in the composition. * * Two PID's are different if any of their three <i>final</i> attributes differ: ip, port, or incarnation. * * Almost every protocol needs to be passed a PID at the constructor which refers to the local process. * This PID is usually called <i>myself</i> * * Once a PID is created it is immutable, this is why it does not need to be cloned to avoid side effects in it. * * It implements the <i>comparable</i> and <i>equals</i> interface. This allows its instances to be ordered in * lists or compared among them. * * It also implements a static method <i>parsePID</i> that contructs an instance of PID based on the data * provided by a string (in a certain format, see parsePID). * */ public class PID implements Comparable, Transportable { /** * IP address of the process. */ //public final InetAddress ip; Change necessary for uka.transport public InetAddress ip; /** * Port of the process. */ public final int port; /** * Incarnation of the process. */ public final int incarnation; private final static String format = new String("{0}:{1,number,#}:{2,number,#}"); /** * Initializes the public fields. * * @param i The IP address * @param p The port * @param z The current incarnation */ public PID(InetAddress i, int p, int z) { ip = i; port = p; incarnation = z; } /** * Returns a hashcode value for this PID. */ public int hashCode() { return (int) ((((long) ip.hashCode()) * ((long) port) * ((long) (incarnation + 1))) & ((long) Integer.MAX_VALUE)); } /** * Indicates if two PIDs represent the same process. * * @param o The other PID. * @return <b>true</b> if both PIDs identify the same process. <b>false </b> otherwise. */ public boolean equals(Object o) { if (!(o instanceof PID)) return false; PID p = (PID) o; return ( ip.equals(p.ip) && port == p.port && incarnation == p.incarnation); } /** * Returns a String representation of this PID. For debugging */ public String toString() { return MessageFormat.format( format, new Object[] { ip.getHostAddress(), new Integer(port), new Integer(incarnation)}); } /** * Compares Two PIDs. * * @param o The PID to compare to <i>this</i> * @return The comparison between both PIDs. */ public int compareTo(Object o) { PID p = (PID) o; // Compares the InetAddress int i = ip.getHostAddress().compareTo(p.ip.getHostAddress()); if (i != 0) { return i; } // Compares the ports i = port - p.port; if (i != 0) { return i; } // Compares the incarnation numbers return (incarnation - p.incarnation); } /** * This static method constructs a new PID instance based on the formatted information given in the * String passed as parameter. * * @param pid The string containing the information of the new PID instance * @return The newly created PID instance * @throws UnknownHostException */ public static PID parsePID(String pid) throws UnknownHostException { MessageFormat mf = new MessageFormat(format); Object[] o = mf.parse(pid, new ParsePosition(0)); return new PID( InetAddress.getByName((String) o[0]), ((Number) o[1]).intValue(), ((Number) o[2]).intValue()); } /** * This method is similar to parsePID, but it uses the console to ask for the ip, port and incarnation. * This method is tipically used in test programs. * It reads the data asked from the BufferedReader passed as parameter. * * @param in The BufferedReader to read the data from * @return A newly created PID instance initialised with data provided through the BufferedReader * @throws IOException */ public static PID readPID(BufferedReader in) throws IOException { String host = null; int port = 0; int incarnation = 0; String str = null; System.out.print( "Host name (ENTER ->" + InetAddress.getLocalHost() + ") :"); host = in.readLine(); if (host.length() == 0) { host = InetAddress.getLocalHost().getHostAddress(); } System.out.print("Port number: "); port = Integer.parseInt(in.readLine()); System.out.print("Incarnation number (ENTER -> 0) :"); str = in.readLine(); if (!str.equals("")) { incarnation = Integer.parseInt(str); } return new PID(InetAddress.getByName(host), port, incarnation); } /* * Code for uka.transport serialization */ //TODO: try 16... if it works, leave it at 16 (for IP6) protected static final int nbytesIP = 4; protected static final int _SIZE = uka.transport.BasicIO.SIZEOF_int + uka.transport.BasicIO.SIZEOF_int + nbytesIP * uka.transport.BasicIO.SIZEOF_byte; /** Used by uka.transport.UnmarshalStream to unmarshal the object */ public PID(uka.transport.UnmarshalStream _stream) throws java.io.IOException, ClassNotFoundException { this(_stream, _SIZE); _stream.accept(_SIZE); } protected PID(uka.transport.UnmarshalStream _stream, int _size) throws java.io.IOException, ClassNotFoundException { _stream.request(_size); byte[] _buffer = _stream.getBuffer(); int _pos = _stream.getPosition(); incarnation = uka.transport.BasicIO.extractInt(_buffer, _pos); _pos += uka.transport.BasicIO.SIZEOF_int; port = uka.transport.BasicIO.extractInt(_buffer, _pos); _pos += uka.transport.BasicIO.SIZEOF_int; byte[] addr = new byte[nbytesIP]; _pos = uka.transport.BasicIO.extract(_buffer, _pos, addr); ip = InetAddress.getByAddress(addr); } /** Method of interface Transportable, it must be declared public. It is called from within UnmarshalStream after creating the object and assigning a stream reference to it. */ public void unmarshalReferences(uka.transport.UnmarshalStream _stream) throws java.io.IOException, ClassNotFoundException { //No references to unmarshall } /** Called directly by uka.transport.MarshalStream */ public void marshal(uka.transport.MarshalStream _stream) throws java.io.IOException { _stream.reserve(_SIZE); byte[] _buffer = _stream.getBuffer(); int _pos = _stream.getPosition(); marshalPrimitives(_buffer, _pos); _stream.deliver(_SIZE); marshalReferences(_stream); } protected void marshalPrimitives(byte[] _buffer, int _pos) throws java.io.IOException { _pos = uka.transport.BasicIO.insert(_buffer, _pos, incarnation); _pos = uka.transport.BasicIO.insert(_buffer, _pos, port); _pos = uka.transport.BasicIO.insert(_buffer, _pos, ip.getAddress()); } protected void marshalReferences(uka.transport.MarshalStream _stream) throws java.io.IOException { } public final Object deepClone(uka.transport.DeepClone _helper) throws CloneNotSupportedException { Object _copy = clone(); _helper.add(this, _copy); ((PID) _copy).deepCloneReferences(_helper); return _copy; } /** Clone all references to other objects. Use the DeepClone to resolve cycles */ protected void deepCloneReferences(uka.transport.DeepClone _helper) throws CloneNotSupportedException { byte[] addr = this.ip.getAddress(); try { InetAddress _copy = InetAddress.getByAddress(addr); _helper.add(this.ip, _copy); this.ip = _copy; } catch (UnknownHostException e) { e.printStackTrace(); System.exit(1); } } }