001: // $Id: LogicalAddress.java,v 1.9 2005/07/17 11:34:20 chrislott Exp $
002:
003: package org.jgroups.stack;
004:
005: import org.jgroups.Address;
006: import org.jgroups.util.Util;
007:
008: import java.io.*;
009: import java.net.InetAddress;
010: import java.net.SocketAddress;
011: import java.util.ArrayList;
012: import java.util.Date;
013: import java.util.List;
014:
015: /**
016: * Logical address that spans the lifetime of a member. Assigned at member (JVM) startup, and
017: * retained until member is shutdown. Note that the address does <em>not</em> change on
018: * disconnect-connect sequences. For example, when a member is shunned and subsequently
019: * readmitted to the group, the member's address (LogicalAddress) remains the same.<br/>
020: * An instance of LogicalAddress is generated by the transport protocol. Currently, only
021: * UDP_NIO generates LogicalAddresses.<br/>
022: * Note that host, timestamp and id are supposed to make LogicalAddress as unique as possible.
023: * However, there is a remote chance that 2 instances started on the same machine create their
024: * address at exactly the same time, resulting in identical addresses (leading to problems).
025: * In the future, I will try to make this totally unique, by for example using the PID of the current
026: * process (once available though the JDK, or by locking on a common resource (e.g. /dev/random)
027: * to serialize creation. However, as for now, chances are you will never experience this problem.
028: * @author Bela Ban, Dec 23 2003
029: */
030: public class LogicalAddress implements Address {
031: protected static int count = 1;
032: protected String host = null;
033: protected long timestamp = 0;
034: protected int id = 0;
035: protected boolean multicast_addr = false;
036:
037: /** Address of the primary physical address. This is set to the sender when a message is received.
038: * If this field is set, we will send unicast messages only to this address, not to all addresses listed
039: * in physical_addrs; this reduces the number of msgs we have to send.<br/>
040: * Note that this field is not shipped across the wire.
041: */
042: transient SocketAddress primary_physical_addr = null;
043:
044: /** List<SocketAddress> of physical addresses */
045: protected ArrayList physical_addrs = null;
046:
047: /** To tack on some additional data */
048: byte[] additional_data = null;
049:
050: // Used only by Externalization
051: public LogicalAddress() {
052: }
053:
054: /** Use this constructor to create an instance, not the null-constructor */
055: public LogicalAddress(String host_name, List physical_addrs) {
056: init(host_name, physical_addrs);
057: }
058:
059: protected void init(String host_name, List physical_addrs) {
060: if (host_name != null) {
061: this .host = host_name;
062: } else {
063: try {
064: host = InetAddress.getLocalHost().getHostName();
065: } catch (Exception e) {
066: host = "localhost";
067: }
068: }
069:
070: timestamp = System.currentTimeMillis();
071:
072: synchronized (LogicalAddress.class) {
073: id = count++;
074: }
075:
076: if (physical_addrs != null) {
077: this .physical_addrs = new ArrayList(physical_addrs);
078: }
079: }
080:
081: public String getHost() {
082: return host;
083: }
084:
085: public long getTimestamp() {
086: return timestamp;
087: }
088:
089: public long getId() {
090: return id;
091: }
092:
093: public SocketAddress getPrimaryPhysicalAddress() {
094: return primary_physical_addr;
095: }
096:
097: public void setPrimaryPhysicalAddress(
098: SocketAddress primary_physical_addr) {
099: this .primary_physical_addr = primary_physical_addr;
100: }
101:
102: /**
103: * Returns a <em>copy</em> of the list of physical addresses. Reason for the copy is that the list is not supposed
104: * to be modified (should be immutable).
105: * @return List of physical addresses (return value maybe null)
106: */
107: public ArrayList getPhysicalAddresses() {
108: return physical_addrs != null ? (ArrayList) physical_addrs
109: .clone() : null;
110: }
111:
112: /**
113: * For internal use only. Don't use this method!
114: * @param addr
115: */
116: public void addPhysicalAddress(SocketAddress addr) {
117: if (addr != null) {
118: if (physical_addrs == null)
119: physical_addrs = new ArrayList();
120: if (!physical_addrs.contains(addr))
121: physical_addrs.add(addr);
122: }
123: }
124:
125: /**
126: * For internal use only. Don't use this method !
127: * @param addr
128: */
129: public void removePhysicalAddress(SocketAddress addr) {
130: if (addr != null && physical_addrs != null)
131: physical_addrs.remove(addr);
132: }
133:
134: /**
135: * For internal use only. Don't use this method !
136: */
137: public void removeAllPhysicalAddresses() {
138: if (physical_addrs != null)
139: physical_addrs.clear();
140: }
141:
142: public boolean isMulticastAddress() {
143: return false; // LogicalAddresses can never be multicast
144: }
145:
146: public int size() {
147: return 22;
148: }
149:
150: /**
151: * Returns the additional_data.
152: * @return byte[]
153: */
154: public byte[] getAdditionalData() {
155: return additional_data;
156: }
157:
158: /**
159: * Sets the additional_data.
160: * @param additional_data The additional_data to set
161: */
162: public void setAdditionalData(byte[] additional_data) {
163: this .additional_data = additional_data;
164: }
165:
166: /**
167: * Establishes an order between 2 addresses. Assumes other contains non-null IpAddress.
168: * Excludes channel_name from comparison.
169: * @return 0 for equality, value less than 0 if smaller, greater than 0 if greater.
170: */
171: public int compare(LogicalAddress other) {
172: return compareTo(other);
173: }
174:
175: /**
176: * implements the java.lang.Comparable interface
177: * @see Comparable
178: * @param o - the Object to be compared
179: * @return a negative integer, zero, or a positive integer as this object is less than,
180: * equal to, or greater than the specified object.
181: * @exception ClassCastException - if the specified object's type prevents it
182: * from being compared to this Object.
183: */
184: public int compareTo(Object o) {
185: int rc;
186:
187: if ((o == null) || !(o instanceof LogicalAddress))
188: throw new ClassCastException(
189: "LogicalAddress.compareTo(): comparison between different classes");
190: LogicalAddress other = (LogicalAddress) o;
191:
192: rc = this .host.compareTo(other.host);
193: if (rc != 0)
194: return rc;
195: if (this .timestamp != other.timestamp)
196: return this .timestamp < other.timestamp ? -1 : 1;
197: if (this .id != other.id)
198: return this .id < other.id ? -1 : 1;
199: return 0;
200: }
201:
202: public boolean equals(Object obj) {
203: if (obj == null)
204: return false;
205: return compareTo(obj) == 0 ? true : false;
206: }
207:
208: public int hashCode() {
209: int retval = (int) (host.hashCode() + timestamp + id);
210: return retval;
211: }
212:
213: public String toString() {
214: return toString(false);
215: }
216:
217: public String toString(boolean print_details) {
218: StringBuffer sb = new StringBuffer();
219:
220: sb.append(host);
221: sb.append(':').append(id);
222: if (print_details) {
223: sb.append(" (created ").append(new Date(timestamp)).append(
224: ')');
225: if (physical_addrs != null)
226: sb.append("\nphysical addrs: ").append(physical_addrs);
227: }
228: if (additional_data != null)
229: sb.append(" (additional data: ").append(
230: additional_data.length).append(" bytes)");
231: return sb.toString();
232: }
233:
234: public void writeExternal(ObjectOutput out) throws IOException {
235: out.writeObject(host);
236: out.writeLong(timestamp);
237: out.writeInt(id);
238:
239: if (physical_addrs != null) {
240: out.writeInt(physical_addrs.size());
241: out.writeObject(physical_addrs);
242: } else
243: out.writeInt(0);
244:
245: if (additional_data != null) {
246: out.writeInt(additional_data.length);
247: out.write(additional_data, 0, additional_data.length);
248: } else
249: out.writeInt(0);
250: }
251:
252: public void readExternal(ObjectInput in) throws IOException,
253: ClassNotFoundException {
254: int len;
255:
256: host = (String) in.readObject();
257: timestamp = in.readLong();
258: id = in.readInt();
259:
260: len = in.readInt();
261: if (len > 0) {
262: physical_addrs = (ArrayList) in.readObject();
263: }
264:
265: len = in.readInt();
266: if (len > 0) {
267: additional_data = new byte[len];
268: in.readFully(additional_data, 0, additional_data.length);
269: }
270: }
271:
272: public void writeTo(DataOutputStream out) throws IOException {
273: Util.writeString(host, out);
274: out.writeLong(timestamp);
275: out.writeInt(id);
276: out.writeBoolean(multicast_addr);
277: ObjectOutputStream oos = new ObjectOutputStream(out);
278: oos.writeObject(physical_addrs);
279: oos.close();
280: Util.writeByteBuffer(additional_data, out);
281: }
282:
283: public void readFrom(DataInputStream in) throws IOException,
284: IllegalAccessException, InstantiationException {
285: host = Util.readString(in);
286: timestamp = in.readLong();
287: id = in.readInt();
288: multicast_addr = in.readBoolean();
289: ObjectInputStream ois = new ObjectInputStream(in);
290: try {
291: physical_addrs = (ArrayList) ois.readObject();
292: } catch (ClassNotFoundException e) {
293: }
294: additional_data = Util.readByteBuffer(in);
295: }
296:
297: public Object clone() throws CloneNotSupportedException {
298: LogicalAddress ret = new LogicalAddress();
299: ret.host = host;
300: ret.timestamp = timestamp;
301: ret.id = id;
302: ret.multicast_addr = multicast_addr;
303: ret.additional_data = additional_data;
304: ret.primary_physical_addr = primary_physical_addr;
305: if (physical_addrs != null)
306: ret.physical_addrs = (ArrayList) physical_addrs.clone();
307: return ret;
308: }
309:
310: public LogicalAddress copy() {
311: try {
312: return (LogicalAddress) clone();
313: } catch (CloneNotSupportedException e) {
314: return null;
315: }
316: }
317:
318: }
|