| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.catalina.cluster.mcast; |
| |
| import org.apache.catalina.cluster.Member; |
| import org.apache.catalina.cluster.io.XByteBuffer; |
| |
| /** |
| * A <b>membership</b> implementation using simple multicast. |
| * This is the representation of a multicast member. |
| * Carries the host, and port of the this or other cluster nodes. |
| * |
| * @author Filip Hanik |
| * @author Peter Rossbach |
| * @version $Revision$, $Date$ |
| */ |
| public class McastMember implements Member, java.io.Serializable { |
| |
| /** |
| * Digits, used for "superfast" de-serialization of an |
| * IP address |
| */ |
| final transient static char[] digits = { |
| '0', '1', '2', '3', '4', '5', |
| '6', '7', '8', '9'}; |
| |
| /** |
| * Public properties specific to this implementation |
| */ |
| public static final transient String TCP_LISTEN_PORT = "tcpListenPort"; |
| public static final transient String TCP_LISTEN_HOST = "tcpListenHost"; |
| public static final transient String MEMBER_NAME = "memberName"; |
| public static final transient String MEMBER_DOMAIN = "memberDomain"; |
| |
| /** |
| * The listen host for this member |
| */ |
| protected String host; |
| /** |
| * The tcp listen port for this member |
| */ |
| protected int port; |
| /** |
| * The name for this member, has be be unique within the cluster. |
| */ |
| private String name; |
| |
| /** |
| * The name of the cluster domain from this node |
| */ |
| private String domain; |
| |
| /** |
| * Counter for how many messages have been sent from this member |
| */ |
| protected int msgCount = 0; |
| /** |
| * The number of milliseconds since this members was |
| * created, is kept track of using the start time |
| */ |
| protected long memberAliveTime = 0; |
| |
| |
| /** |
| * Construct a new member object |
| * @param name - the name of this member, cluster unique |
| * @param domain - the cluster domain name of this member |
| * @param host - the tcp listen host |
| * @param port - the tcp listen port |
| */ |
| public McastMember(String name, |
| String domain, |
| String host, |
| int port, |
| long aliveTime) { |
| this.host = host; |
| this.port = port; |
| this.name = name; |
| this.domain = domain; |
| this.memberAliveTime=aliveTime; |
| } |
| |
| /** |
| * |
| * @return a Hashmap containing the following properties:<BR> |
| * 1. tcpListenPort - the port this member listens to for messages - string<BR> |
| * 2. tcpListenHost - the host address of this member - string<BR> |
| * 3. memberName - the name of this member - string<BR> |
| */ |
| public java.util.HashMap getMemberProperties() { |
| java.util.HashMap map = new java.util.HashMap(2); |
| map.put(McastMember.TCP_LISTEN_HOST,this.host); |
| map.put(McastMember.TCP_LISTEN_PORT,String.valueOf(this.port)); |
| map.put(McastMember.MEMBER_NAME,name); |
| map.put(McastMember.MEMBER_DOMAIN,domain); |
| return map; |
| } |
| |
| /** |
| * Increment the message count. |
| */ |
| protected void inc() { |
| msgCount++; |
| } |
| |
| /** |
| * Create a data package to send over the wire representing this member. |
| * This is faster than serialization. |
| * @return - the bytes for this member deserialized |
| * @throws Exception |
| */ |
| protected byte[] getData(long startTime) throws Exception { |
| //package looks like |
| //alive - 8 bytes |
| //port - 4 bytes |
| //host - 4 bytes |
| //nlen - 4 bytes |
| //name - nlen bytes |
| //dlen - 4 bytes |
| //domain - dlen bytes |
| byte[] named = getName().getBytes(); |
| byte[] domaind = getDomain().getBytes(); |
| byte[] addr = java.net.InetAddress.getByName(host).getAddress(); |
| byte[] data = new byte[8+4+addr.length+4+named.length+4+domaind.length]; |
| long alive=System.currentTimeMillis()-startTime; |
| System.arraycopy(XByteBuffer.toBytes((long)alive),0,data,0,8); |
| System.arraycopy(XByteBuffer.toBytes(port),0,data,8,4); |
| System.arraycopy(addr,0,data,12,addr.length); |
| System.arraycopy(XByteBuffer.toBytes(named.length),0,data,16,4); |
| System.arraycopy(named,0,data,20,named.length); |
| System.arraycopy(XByteBuffer.toBytes(domaind.length),0,data,named.length+20,4); |
| System.arraycopy(domaind,0,data,named.length+24,domaind.length); |
| return data; |
| } |
| /** |
| * Deserializes a member from data sent over the wire |
| * @param data - the bytes received |
| * @return a member object. |
| */ |
| protected static McastMember getMember(byte[] data) { |
| //package looks like |
| //alive - 8 bytes |
| //port - 4 bytes |
| //host - 4 bytes |
| //nlen - 4 bytes |
| //name - nlen bytes |
| //dlen - 4 bytes |
| //domain - dlen bytes |
| byte[] alived = new byte[8]; |
| System.arraycopy(data, 0, alived, 0, 8); |
| byte[] portd = new byte[4]; |
| System.arraycopy(data, 8, portd, 0, 4); |
| byte[] addr = new byte[4]; |
| System.arraycopy(data, 12, addr, 0, 4); |
| //FIXME control the nlen |
| byte[] nlend = new byte[4]; |
| System.arraycopy(data, 16, nlend, 0, 4); |
| int nlen = XByteBuffer.toInt(nlend, 0); |
| byte[] named = new byte[nlen]; |
| System.arraycopy(data, 20, named, 0, named.length); |
| //FIXME control the dlen |
| byte[] dlend = new byte[4]; |
| System.arraycopy(data, nlen + 20, dlend, 0, 4); |
| int dlen = XByteBuffer.toInt(dlend, 0); |
| byte[] domaind = new byte[dlen]; |
| System.arraycopy(data, nlen + 24, domaind, 0, domaind.length); |
| return new McastMember(new String(named), |
| new String(domaind), |
| addressToString(addr), |
| XByteBuffer.toInt(portd, 0), |
| XByteBuffer.toLong(alived, 0)); |
| } |
| |
| /** |
| * Return the name of this object |
| * @return a unique name to the cluster |
| */ |
| public String getName() { |
| return name; |
| } |
| |
| /** |
| * Return the domain of this object |
| * @return a cluster domain to the cluster |
| */ |
| public String getDomain() { |
| return domain; |
| } |
| |
| /** |
| * Return the listen port of this member |
| * @return - tcp listen port |
| */ |
| public int getPort() { |
| return this.port; |
| } |
| |
| /** |
| * Return the TCP listen host for this member |
| * @return IP address or host name |
| */ |
| public String getHost() { |
| return this.host; |
| } |
| |
| /** |
| * Contains information on how long this member has been online. |
| * The result is the number of milli seconds this member has been |
| * broadcasting its membership to the cluster. |
| * @return nr of milliseconds since this member started. |
| */ |
| public long getMemberAliveTime() { |
| return memberAliveTime; |
| } |
| |
| public void setMemberAliveTime(long time) { |
| memberAliveTime=time; |
| } |
| |
| |
| |
| /** |
| * String representation of this object |
| */ |
| public String toString() { |
| return "org.apache.catalina.cluster.mcast.McastMember["+name+","+domain+","+host+","+port+", alive="+memberAliveTime+"]"; |
| } |
| |
| /** |
| * @see java.lang.Object#hashCode() |
| * @return The hash code |
| */ |
| public int hashCode() { |
| return this.name.hashCode(); |
| } |
| |
| /** |
| * Returns true if the param o is a McastMember with the same name |
| * @param o |
| */ |
| public boolean equals(Object o) { |
| if ( o instanceof McastMember ) { |
| return this.name.equals(((McastMember)o).getName()); |
| } |
| else |
| return false; |
| } |
| |
| /** |
| * Converts for bytes (ip address) to a string representation of it<BR> |
| * Highly optimized method. |
| * @param address (4 bytes ip address) |
| * @return string representation of that ip address |
| */ |
| private static final String addressToString(byte[] address) { |
| int q, r = 0; |
| int charPos = 15; |
| char[] buf = new char[15]; |
| char dot = '.'; |
| |
| int i = address[3] & 0xFF; |
| for (; ; ) |
| { |
| q = (i * 52429) >>> (19); |
| r = i - ( (q << 3) + (q << 1)); |
| buf[--charPos] = digits[r]; |
| i = q; |
| if (i == 0) |
| break; |
| } |
| buf[--charPos] = dot; |
| i = address[2] & 0xFF; |
| for (; ; ) |
| { |
| q = (i * 52429) >>> (19); |
| r = i - ( (q << 3) + (q << 1)); |
| buf[--charPos] = digits[r]; |
| i = q; |
| if (i == 0) |
| break; |
| } |
| buf[--charPos] = dot; |
| |
| i = address[1] & 0xFF; |
| for (; ; ) |
| { |
| q = (i * 52429) >>> (19); |
| r = i - ( (q << 3) + (q << 1)); |
| buf[--charPos] = digits[r]; |
| i = q; |
| if (i == 0) |
| break; |
| } |
| |
| buf[--charPos] = dot; |
| i = address[0] & 0xFF; |
| |
| for (; ; ) |
| { |
| q = (i * 52429) >>> (19); |
| r = i - ( (q << 3) + (q << 1)); |
| buf[--charPos] = digits[r]; |
| i = q; |
| if (i == 0) |
| break; |
| } |
| return new String(buf, charPos, 15 - charPos); |
| } |
| public void setHost(String host) { |
| this.host = host; |
| } |
| public void setMsgCount(int msgCount) { |
| this.msgCount = msgCount; |
| } |
| public void setName(String name) { |
| this.name = name; |
| } |
| public void setDomain(String domain) { |
| this.domain = domain; |
| } |
| public void setPort(int port) { |
| this.port = port; |
| } |
| } |