001: /*
002: * Copyright 1999,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.catalina.cluster.mcast;
018:
019: import org.apache.catalina.cluster.Member;
020:
021: /**
022: * A <b>membership</b> implementation using simple multicast.
023: * This is the representation of a multicast member.
024: * Carries the host, and port of the this or other cluster nodes.
025: *
026: * @author Filip Hanik
027: * @version $Revision: 1.5 $, $Date: 2004/05/26 16:35:54 $
028: */
029:
030: import org.apache.catalina.cluster.io.XByteBuffer;
031:
032: public class McastMember implements Member, java.io.Serializable {
033:
034: /**
035: * Digits, used for "superfast" de-serialization of an
036: * IP address
037: */
038: final transient static char[] digits = { '0', '1', '2', '3', '4',
039: '5', '6', '7', '8', '9' };
040:
041: /**
042: * Public properties specific to this implementation
043: */
044: public static final transient String TCP_LISTEN_PORT = "tcpListenPort";
045: public static final transient String TCP_LISTEN_HOST = "tcpListenHost";
046: public static final transient String MEMBER_NAME = "memberName";
047:
048: /**
049: * The listen host for this member
050: */
051: protected String host;
052: /**
053: * The tcp listen port for this member
054: */
055: protected int port;
056: /**
057: * The name for this member, has be be unique within the cluster.
058: */
059: private String name;
060: /**
061: * Counter for how many messages have been sent from this member
062: */
063: protected int msgCount = 0;
064: /**
065: * The number of milliseconds since this members was
066: * created, is kept track of using the start time
067: */
068: protected long memberAliveTime = 0;
069:
070: /**
071: * Construct a new member object
072: * @param name - the name of this member, cluster unique
073: * @param host - the tcp listen host
074: * @param port - the tcp listen port
075: */
076: public McastMember(String name, String host, int port,
077: long aliveTime) {
078: this .host = host;
079: this .port = port;
080: this .name = name;
081: this .memberAliveTime = aliveTime;
082: }
083:
084: /**
085: *
086: * @return a Hashmap containing the following properties:<BR>
087: * 1. tcpListenPort - the port this member listens to for messages - string<BR>
088: * 2. tcpListenHost - the host address of this member - string<BR>
089: * 3. memberName - the name of this member - string<BR>
090: */
091: public java.util.HashMap getMemberProperties() {
092: java.util.HashMap map = new java.util.HashMap(2);
093: map.put(this .TCP_LISTEN_HOST, this .host);
094: map.put(this .TCP_LISTEN_PORT, String.valueOf(this .port));
095: map.put(this .MEMBER_NAME, name);
096: return map;
097: }
098:
099: /**
100: * Increment the message count.
101: */
102: protected void inc() {
103: msgCount++;
104: }
105:
106: /**
107: * Create a data package to send over the wire representing this member.
108: * This is faster than serialization.
109: * @return - the bytes for this member deserialized
110: * @throws Exception
111: */
112: protected byte[] getData(long startTime) throws Exception {
113: //package looks like
114: //alive - 8 bytes
115: //port - 4 bytes
116: //host - 4 bytes
117: //name - remaining bytes
118: byte[] named = getName().getBytes();
119: byte[] addr = java.net.InetAddress.getByName(host).getAddress();
120: byte[] data = new byte[8 + 4 + addr.length + named.length];
121: long alive = System.currentTimeMillis() - startTime;
122: System.arraycopy(XByteBuffer.toBytes((long) alive), 0, data, 0,
123: 8);
124: System.arraycopy(XByteBuffer.toBytes(port), 0, data, 8, 4);
125: System.arraycopy(addr, 0, data, 12, addr.length);
126: System.arraycopy(named, 0, data, 8 + 4 + addr.length,
127: named.length);
128: return data;
129: }
130:
131: /**
132: * Deserializes a member from data sent over the wire
133: * @param data - the bytes received
134: * @return a member object.
135: */
136: protected static McastMember getMember(byte[] data) {
137: //package looks like
138: //alive - 8 bytes
139: //port - 4 bytes
140: //host - 4 bytes
141: //name - remaining bytes
142: byte[] alived = new byte[8];
143: System.arraycopy(data, 0, alived, 0, 8);
144: byte[] portd = new byte[4];
145: System.arraycopy(data, 8, portd, 0, 4);
146: byte[] addr = new byte[4];
147: System.arraycopy(data, 12, addr, 0, 4);
148: byte[] named = new byte[data.length - 16];
149: System.arraycopy(data, 16, named, 0, named.length);
150: return new McastMember(new String(named),
151: addressToString(addr), XByteBuffer.toInt(portd, 0),
152: XByteBuffer.toLong(alived, 0));
153: }
154:
155: /**
156: * Return the name of this object
157: * @return a unique name to the cluster
158: */
159: public String getName() {
160: return name;
161: }
162:
163: /**
164: * Return the listen port of this member
165: * @return - tcp listen port
166: */
167: public int getPort() {
168: return this .port;
169: }
170:
171: /**
172: * Return the TCP listen host for this member
173: * @return IP address or host name
174: */
175: public String getHost() {
176: return this .host;
177: }
178:
179: /**
180: * Contains information on how long this member has been online.
181: * The result is the number of milli seconds this member has been
182: * broadcasting its membership to the cluster.
183: * @return nr of milliseconds since this member started.
184: */
185: public long getMemberAliveTime() {
186: return memberAliveTime;
187: }
188:
189: public void setMemberAliveTime(long time) {
190: memberAliveTime = time;
191: }
192:
193: /**
194: * String representation of this object
195: */
196: public String toString() {
197: return "org.apache.catalina.cluster.mcast.McastMember[" + name
198: + "," + host + "," + port + ", alive="
199: + memberAliveTime + "]";
200: }
201:
202: /**
203: * @see java.lang.Object#hashCode()
204: * @return
205: */
206: public int hashCode() {
207: return this .name.hashCode();
208: }
209:
210: /**
211: * Returns true if the param o is a McastMember with the same name
212: * @param o
213: */
214: public boolean equals(Object o) {
215: if (o instanceof McastMember) {
216: return this .name.equals(((McastMember) o).getName());
217: } else
218: return false;
219: }
220:
221: /**
222: * Converts for bytes (ip address) to a string representation of it<BR>
223: * Highly optimized method.
224: * @param address (4 bytes ip address)
225: * @return string representation of that ip address
226: */
227: private static final String addressToString(byte[] address) {
228: int q, r = 0;
229: int charPos = 15;
230: char[] buf = new char[15];
231: char dot = '.';
232:
233: int i = address[3] & 0xFF;
234: for (;;) {
235: q = (i * 52429) >>> (19);
236: r = i - ((q << 3) + (q << 1));
237: buf[--charPos] = digits[r];
238: i = q;
239: if (i == 0)
240: break;
241: }
242: buf[--charPos] = dot;
243: i = address[2] & 0xFF;
244: for (;;) {
245: q = (i * 52429) >>> (19);
246: r = i - ((q << 3) + (q << 1));
247: buf[--charPos] = digits[r];
248: i = q;
249: if (i == 0)
250: break;
251: }
252: buf[--charPos] = dot;
253:
254: i = address[1] & 0xFF;
255: for (;;) {
256: q = (i * 52429) >>> (19);
257: r = i - ((q << 3) + (q << 1));
258: buf[--charPos] = digits[r];
259: i = q;
260: if (i == 0)
261: break;
262: }
263:
264: buf[--charPos] = dot;
265: i = address[0] & 0xFF;
266:
267: for (;;) {
268: q = (i * 52429) >>> (19);
269: r = i - ((q << 3) + (q << 1));
270: buf[--charPos] = digits[r];
271: i = q;
272: if (i == 0)
273: break;
274: }
275: return new String(buf, charPos, 15 - charPos);
276: }
277:
278: public void setHost(String host) {
279: this .host = host;
280: }
281:
282: public void setMsgCount(int msgCount) {
283: this .msgCount = msgCount;
284: }
285:
286: public void setName(String name) {
287: this .name = name;
288: }
289:
290: public void setPort(int port) {
291: this.port = port;
292: }
293: }
|