| /*========================================================================= |
| * Copyright (c) 2002-2014 Pivotal Software, Inc. All Rights Reserved. |
| * This product is protected by U.S. and international copyright |
| * and intellectual property laws. Pivotal products are covered by |
| * more patents listed at http://www.pivotal.io/patents. |
| *========================================================================= |
| */ |
| package com.gemstone.gemfire.distributed.internal.membership; |
| |
| import com.gemstone.gemfire.DataSerializer; |
| import com.gemstone.gemfire.InternalGemFireError; |
| import com.gemstone.gemfire.cache.UnsupportedVersionException; |
| import com.gemstone.gemfire.distributed.DistributedMember; |
| import com.gemstone.gemfire.distributed.DurableClientAttributes; |
| import com.gemstone.gemfire.distributed.Role; |
| import com.gemstone.gemfire.distributed.internal.DistributionManager; |
| import com.gemstone.gemfire.distributed.internal.DistributionAdvisor.ProfileId; |
| import com.gemstone.gemfire.distributed.internal.membership.jgroup.GFJGBasicAdapter; |
| import com.gemstone.gemfire.distributed.internal.membership.jgroup.GFJGPeerAdapter; |
| import com.gemstone.gemfire.distributed.internal.membership.jgroup.JGroupMember; |
| import com.gemstone.gemfire.internal.Assert; |
| import com.gemstone.gemfire.internal.DataSerializableFixedID; |
| import com.gemstone.gemfire.internal.InternalDataSerializer; |
| import com.gemstone.gemfire.internal.SocketCreator; |
| import com.gemstone.gemfire.internal.Version; |
| import com.gemstone.gemfire.internal.cache.versions.VersionSource; |
| import com.gemstone.gemfire.internal.i18n.LocalizedStrings; |
| import com.gemstone.org.jgroups.stack.IpAddress; |
| |
| import java.io.DataInput; |
| import java.io.DataOutput; |
| import java.io.Externalizable; |
| import java.io.IOException; |
| import java.io.ObjectInput; |
| import java.io.ObjectOutput; |
| import java.io.Serializable; |
| import java.net.InetAddress; |
| import java.net.UnknownHostException; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| import java.net.Inet4Address; |
| |
| /** |
| * This is the fundamental representation of a member of a GemFire distributed |
| * system. |
| * |
| * Unfortunately, this class serves two distinct functions. First, it is the |
| * fundamental element of membership in the GemFire distributed system. As such, |
| * it is used in enumerations and properly responds to hashing and equals() |
| * comparisons. |
| * |
| * Second, it is used as a cheap way of representing an address. This is |
| * unfortunate, because as a NetMember, it holds two separate port numbers: the |
| * "membership" descriptor as well as a direct communication channel. |
| * |
| * TODO fix this. |
| */ |
| public final class InternalDistributedMember |
| implements DistributedMember, |
| Externalizable, DataSerializableFixedID, ProfileId, |
| VersionSource<DistributedMember> |
| { |
| private final static long serialVersionUID = -2785249969777296507L; |
| |
| protected NetMember ipAddr; // the underlying member object, e.g. from JGroups |
| // private IpAddress ipAddr; |
| |
| /** |
| * This is the direct channel port. The underlying NetMember must be able to |
| * serialize and deliver this value. |
| */ |
| private int dcPort = -1; |
| |
| /** |
| * This is the process id of this member on its machine. The underlying |
| * NetMember must be able to serialize and deliver this value. |
| */ |
| private int vmPid = -1; |
| |
| /** |
| * This is a representation of the type of VM. The underlying NetMember must |
| * be able to serialize and deliver this value. |
| */ |
| private int vmKind = -1; |
| |
| /** |
| * This is the view identifier where this ID was born, or zero if this is |
| * a loner member |
| */ |
| private int vmViewId = -1; |
| |
| /** |
| * whether this is a partial member ID (without roles, durable attributes). |
| * We use partial IDs in EventID objects to reduce their size. It would be |
| * better to use canonical IDs but there is currently no central mechanism |
| * that would allow that for both server and client identifiers |
| */ |
| private boolean isPartial; |
| |
| /** Internal list of group/role names for this member. */ |
| private String[] groups; |
| |
| /** |
| * The roles, if any, of this member. Lazily created first time getRoles() |
| * is called. |
| */ |
| private volatile Set<Role> rolesSet = null; |
| |
| /** lock object used when getting/setting roles/rolesSet fields */ |
| private final Object rolesLock = new Object(); |
| |
| /** |
| * The name of this member's distributed system connection. |
| * @see com.gemstone.gemfire.distributed.DistributedSystem#getName |
| */ |
| private String name = null; |
| |
| /** |
| * Unique tag (such as randomly generated bytes) to help enforce uniqueness. |
| * Note: this should be displayable. |
| */ |
| private String uniqueTag = null; |
| |
| /** serialization bit mask */ |
| private static final int SB_ENABLED_MASK = 0x1; |
| |
| /** serialization bit mask */ |
| private static final int COORD_ENABLED_MASK = 0x2; |
| |
| /** partial ID bit mask */ |
| private static final int PARTIAL_ID_MASK = 0x4; |
| |
| /** product version bit mask */ |
| private static final int VERSION_MASK = 0x8; |
| |
| /** |
| * Representing the host name of this member. |
| */ |
| private String hostName = null; |
| |
| private transient short version = Version.CURRENT_ORDINAL; |
| private transient Version versionObj = Version.CURRENT; |
| |
| /** |
| * User-defined attributes (id and timeout) used by durable clients. |
| */ |
| private DurableClientAttributes durableClientAttributes = null; |
| |
| /** The versions in which this message was modified */ |
| private static final Version[] dsfidVersions = new Version[] { |
| Version.GFE_71 }; |
| |
| private void defaultToCurrentHost() { |
| int defaultDcPort = MemberAttributes.DEFAULT.getPort(); |
| // [bruce] disabled to allow loners to modify the ID post-connect |
| // Assert.assertTrue(defaultDcPort > 0); |
| |
| this.dcPort = defaultDcPort;; |
| this.vmKind = MemberAttributes.DEFAULT.getVmKind(); |
| this.vmPid = MemberAttributes.DEFAULT.getVmPid(); |
| this.name = MemberAttributes.DEFAULT.getName(); |
| this.groups = MemberAttributes.DEFAULT.getGroups(); |
| this.vmViewId = MemberAttributes.DEFAULT.getVmViewId(); |
| this.durableClientAttributes = MemberAttributes.DEFAULT.getDurableClientAttributes(); |
| if (this.ipAddr instanceof JGroupMember) { |
| ((JGroupMember)this.ipAddr).getAddress().setProcessId(this.vmPid); |
| } |
| try { |
| if (SocketCreator.resolve_dns) { |
| this.hostName = SocketCreator.getHostName(SocketCreator.getLocalHost()); |
| } |
| else { |
| this.hostName = SocketCreator.getLocalHost().getHostAddress(); |
| } |
| } |
| catch(UnknownHostException ee){ |
| throw new InternalGemFireError(ee); |
| } |
| // checkHostName(); |
| } |
| |
| |
| // Used only by Externalization |
| public InternalDistributedMember() { |
| this.groups = new String[0]; |
| } |
| |
| /** |
| * Construct a InternalDistributedMember. All fields are specified.<p> |
| * |
| * This, and the following constructor are the only valid ways to create an ID |
| * for a distributed member for use |
| * in the P2P cache. Use of other constructors can break network-partition-detection. |
| * |
| * @param i |
| * @param p |
| * the membership port |
| * @param splitBrainEnabled whether this feature is enabled for the member |
| * @param canBeCoordinator whether the member is eligible to be the membership coordinator |
| * @param attr |
| * the member's attributes |
| */ |
| public InternalDistributedMember(InetAddress i, int p, |
| boolean splitBrainEnabled, boolean canBeCoordinator, MemberAttributes attr) { |
| this.dcPort = attr.getPort(); |
| this.vmPid = attr.getVmPid(); |
| this.vmKind = attr.getVmKind(); |
| this.vmViewId = attr.getVmViewId(); |
| this.name = attr.getName(); |
| this.groups = attr.getGroups(); |
| this.durableClientAttributes = attr.getDurableClientAttributes(); |
| this.ipAddr = MemberFactory.newNetMember(i, p, splitBrainEnabled, canBeCoordinator, attr); |
| this.hostName = SocketCreator.resolve_dns? SocketCreator.getHostName(i) : i.getHostAddress(); |
| // checkHostName(); |
| } |
| |
| /** |
| * Construct a InternalDistributedMember based on the given NetMember.<p> |
| * This is not the preferred way of creating an instance since the NetMember |
| * may not have all required information (e.g., a JGroups address without |
| * direct-port and other information). |
| * @param m |
| */ |
| public InternalDistributedMember(NetMember m) { |
| ipAddr = m; |
| |
| MemberAttributes attr = m.getAttributes(); |
| this.hostName = SocketCreator.resolve_dns? SocketCreator.getHostName(m.getIpAddress()) : |
| m.getIpAddress().getHostAddress(); |
| // checkHostName(); |
| if (attr == null) { |
| // no extended information available, so this address is crippled |
| } |
| else { |
| this.dcPort = attr.getPort(); |
| this.vmPid = attr.getVmPid(); |
| this.vmKind = attr.getVmKind(); |
| this.vmViewId = attr.getVmViewId(); |
| this.name = attr.getName(); |
| this.groups = attr.getGroups(); |
| this.durableClientAttributes = attr.getDurableClientAttributes(); |
| } |
| final IpAddress addr = ((JGroupMember)m).getAddress(); |
| this.version = addr.getVersionOrdinal(); |
| try { |
| this.versionObj = Version.fromOrdinal(version, false); |
| } catch (UnsupportedVersionException e) { |
| this.versionObj = Version.CURRENT; |
| } |
| cachedToString = null; |
| } |
| |
| // private void checkHostName() { |
| // // bug #44858: debug method to find who is putting a host name instead of addr into an ID |
| // if (!SocketCreator.resolve_dns |
| // && this.hostName != null && this.hostName.length() > 0 |
| // && !Character.isDigit(this.hostName.charAt(0))) { |
| // throw new RuntimeException("found hostname that doesn't start with a digit: " + this.hostName); |
| // } |
| // } |
| |
| /** |
| * Create a InternalDistributedMember referring to the current host (as defined by the given |
| * string).<p> |
| * |
| * <b> |
| * [bruce]THIS METHOD IS FOR TESTING ONLY. DO NOT USE IT TO CREATE IDs FOR |
| * USE IN THE PRODUCT. IT DOES NOT PROPERLY INITIALIZE ATTRIBUTES NEEDED |
| * FOR P2P FUNCTIONALITY. |
| * </b> |
| * |
| * |
| * @param i |
| * the hostname, must be for the current host |
| * @param p |
| * the membership listening port |
| * @throws UnknownHostException if the given hostname cannot be resolved |
| */ |
| public InternalDistributedMember(String i, int p) throws UnknownHostException { |
| ipAddr = MemberFactory.newNetMember(i, p); |
| defaultToCurrentHost(); |
| this.vmKind = DistributionManager.NORMAL_DM_TYPE; |
| GFJGBasicAdapter.insertDefaultGemFireAttributes(((JGroupMember)ipAddr).getAddress()); |
| } |
| |
| /** |
| * Create a InternalDistributedMember referring to the current host |
| * (as defined by the given string) with additional info including optional |
| * connection name and an optional unique string. Currently these two |
| * optional fields (and this constructor) are only used by the |
| * LonerDistributionManager.<p> |
| * |
| * < b> |
| * [bruce]DO NOT USE THIS METHOD TO CREATE ANYTHING OTHER THAN A LONER ID |
| * WITHOUT TALKING TO ME FIRST. IT DOES NOT PROPERLY INITIALIZE THE ID. |
| * </b> |
| * |
| * @param i |
| * the hostname, must be for the current host |
| * @param p |
| * the membership listening port |
| * @param n |
| * gemfire properties connection name |
| * @param u |
| * unique string used make the member more unique |
| * @throws UnknownHostException if the given hostname cannot be resolved |
| */ |
| public InternalDistributedMember(String i, int p, String n, String u) throws UnknownHostException { |
| ipAddr = MemberFactory.newNetMember(i, p); |
| defaultToCurrentHost(); |
| GFJGBasicAdapter.insertDefaultGemFireAttributes(((JGroupMember)ipAddr).getAddress()); |
| this.name = n; |
| this.uniqueTag = u; |
| } |
| |
| /** |
| * Create a InternalDistributedMember referring to the current host (as defined by the given |
| * address).<p> |
| * |
| * <b> |
| * [bruce]THIS METHOD IS FOR TESTING ONLY. DO NOT USE IT TO CREATE IDs FOR |
| * USE IN THE PRODUCT. IT DOES NOT PROPERLY INITIALIZE ATTRIBUTES NEEDED |
| * FOR P2P FUNCTIONALITY. |
| * </b> |
| * |
| * |
| * @param i |
| * the hostname, must be for the current host |
| * @param p |
| * the membership listening port |
| */ |
| public InternalDistributedMember(InetAddress i, int p) { |
| ipAddr = MemberFactory.newNetMember(i, p); |
| defaultToCurrentHost(); |
| } |
| |
| /** |
| * Create a InternalDistributedMember as defined by the given address. |
| * <p> |
| * |
| * <b> |
| * [bruce]THIS METHOD IS FOR TESTING ONLY. DO NOT USE IT TO CREATE IDs FOR |
| * USE IN THE PRODUCT. IT DOES NOT PROPERLY INITIALIZE ATTRIBUTES NEEDED |
| * FOR P2P FUNCTIONALITY. |
| * </b> |
| * |
| * @param addr |
| * address of the server |
| * @param p |
| * the listening port of the server |
| * @param isCurrentHost |
| * true if the given host refers to the current host (bridge and |
| * gateway use false to create a temporary id for the OTHER side of a |
| * connection) |
| */ |
| public InternalDistributedMember(InetAddress addr, |
| int p, |
| boolean isCurrentHost) { |
| ipAddr = MemberFactory.newNetMember(addr, p); |
| if (isCurrentHost) { |
| defaultToCurrentHost(); |
| } |
| } |
| |
| /** |
| * Return the underlying host address |
| * |
| * @return the underlying host address |
| */ |
| public InetAddress getIpAddress() |
| { |
| return ipAddr.getIpAddress(); |
| } |
| |
| public NetMember getNetMember() { |
| return ipAddr; |
| } |
| |
| /** |
| * Return the underlying port (membership port) |
| * @return the underlying membership port |
| */ |
| public int getPort() |
| { |
| return ipAddr.getPort(); |
| } |
| |
| |
| /** |
| * Returns the port on which the direct channel runs |
| */ |
| public int getDirectChannelPort() |
| { |
| assert !this.isPartial; |
| return dcPort; |
| } |
| |
| /** |
| * [GemStone] Returns the kind of VM that hosts the distribution manager with |
| * this address. |
| * |
| * @see com.gemstone.gemfire.distributed.internal.DistributionManager#getDistributionManagerType |
| * @see com.gemstone.gemfire.distributed.internal.DistributionManager#NORMAL_DM_TYPE |
| */ |
| public int getVmKind() |
| { |
| return vmKind; |
| } |
| |
| /** |
| * Returns the membership view ID that this member was born in. For |
| * backward compatibility reasons this is limited to 16 bits. |
| */ |
| public int getVmViewId() { |
| return this.vmViewId; |
| } |
| |
| /** |
| * Returns an unmodifiable Set of this member's Roles. |
| */ |
| public Set<Role> getRoles() { |
| Set<Role> tmpRolesSet = this.rolesSet; |
| if (tmpRolesSet != null) { |
| return tmpRolesSet; |
| } |
| assert !this.isPartial; |
| synchronized (this.rolesLock) { |
| tmpRolesSet = this.rolesSet; |
| if (tmpRolesSet == null) { |
| final String[] tmpRoles = this.groups; |
| // convert array of string role names to array of Roles... |
| if (tmpRoles.length == 0) { |
| tmpRolesSet = Collections.emptySet(); |
| } |
| else { |
| tmpRolesSet = new HashSet<Role>(tmpRoles.length); |
| for (int i = 0; i < tmpRoles.length; i++) { |
| tmpRolesSet.add(InternalRole.getRole(tmpRoles[i])); |
| } |
| tmpRolesSet = Collections.unmodifiableSet(tmpRolesSet); |
| } |
| this.rolesSet = tmpRolesSet; |
| } |
| } |
| Assert.assertTrue(tmpRolesSet != null); |
| return tmpRolesSet; |
| } |
| public List<String> getGroups() { |
| return Collections.unmodifiableList(Arrays.asList(this.groups)); |
| } |
| |
| public void setGroups(String[] newGroups) { |
| assert !this.isPartial; |
| assert newGroups != null; |
| synchronized (this.rolesLock) { |
| this.groups = newGroups; |
| synchPayload(); |
| this.rolesSet = null; |
| this.cachedToString = null; |
| } |
| } |
| |
| private void synchPayload() { |
| ipAddr.setAttributes(new MemberAttributes(dcPort, vmPid, vmKind, |
| vmViewId, name, groups, durableClientAttributes)); |
| } |
| |
| public void setVmKind(int p) |
| { |
| vmKind = p; |
| synchPayload(); |
| cachedToString = null; |
| } |
| |
| public void setVmViewId(int p) { |
| this.vmViewId = p; |
| synchPayload(); |
| } |
| |
| /** |
| * [GemStone] Returns the process id of the VM that hosts the distribution |
| * manager with this address. |
| * |
| * @since 4.0 |
| */ |
| public int getVmPid() |
| { |
| return vmPid; |
| } |
| |
| /** |
| * [GemStone] Sets the process id of the VM that hosts the distribution |
| * manager with this address. |
| * |
| * @since 4.0 |
| */ |
| public void setVmPid(int p) |
| { |
| this.vmPid = p; |
| synchPayload(); |
| cachedToString = null; |
| } |
| |
| /** |
| * Returns the name of this member's distributed system connection or null |
| * if no name was specified. |
| * @see com.gemstone.gemfire.distributed.DistributedSystem#getName |
| */ |
| public String getName() { |
| String result = this.name; |
| if (result == null) { |
| result = ""; |
| } |
| return result; |
| } |
| |
| /** |
| * Returns this member's unique tag (such as randomly generated bytes) or |
| * null if no unique tag was created. |
| */ |
| public String getUniqueTag() { |
| return this.uniqueTag; |
| } |
| |
| /** |
| * Returns this client member's durable attributes or null if no durable |
| * attributes were created. |
| */ |
| public DurableClientAttributes getDurableClientAttributes() { |
| assert !this.isPartial; |
| return this.durableClientAttributes; |
| } |
| |
| /** |
| * implements the java.lang.Comparable interface |
| * |
| * @see java.lang.Comparable |
| * @param o - |
| * the Object to be compared |
| * @return a negative integer, zero, or a positive integer as this object is |
| * less than, equal to, or greater than the specified object. |
| * @exception java.lang.ClassCastException - |
| * if the specified object's type prevents it from being compared |
| * to this Object. |
| */ |
| public int compareTo(DistributedMember o) |
| { |
| if (this == o) { |
| return 0; |
| } |
| // obligatory type check |
| if ((o == null) || !(o instanceof InternalDistributedMember)) |
| throw new ClassCastException(LocalizedStrings.InternalDistributedMember_INTERNALDISTRIBUTEDMEMBERCOMPARETO_COMPARISON_BETWEEN_DIFFERENT_CLASSES.toLocalizedString()); |
| InternalDistributedMember other = (InternalDistributedMember)o; |
| |
| int myPort = getPort(); |
| int otherPort = other.getPort(); |
| if (myPort < otherPort) |
| return -1; |
| if (myPort > otherPort) |
| return 1; |
| |
| |
| InetAddress myAddr = getIpAddress(); |
| InetAddress otherAddr = other.getIpAddress(); |
| |
| // Discard null cases |
| if (myAddr == null && otherAddr == null) { |
| if (myPort < otherPort) |
| return -1; |
| else if (myPort > otherPort) |
| return 1; |
| else |
| return 0; |
| } |
| else if (myAddr == null) { |
| return -1; |
| } |
| else if (otherAddr == null) |
| return 1; |
| |
| byte[] myBytes = myAddr.getAddress(); |
| byte[] otherBytes = otherAddr.getAddress(); |
| |
| if (myBytes != otherBytes) { |
| for (int i = 0; i < myBytes.length; i++) { |
| if (i >= otherBytes.length) |
| return -1; // same as far as they go, but shorter... |
| if (myBytes[i] < otherBytes[i]) |
| return -1; |
| if (myBytes[i] > otherBytes[i]) |
| return 1; |
| } |
| if (myBytes.length > otherBytes.length) |
| return 1; // same as far as they go, but longer... |
| } |
| |
| if (this.name == null && other.name == null) { |
| // do nothing |
| } else if (this.name == null) { |
| return -1; |
| } |
| else if (other.name == null) { |
| return 1; |
| } |
| else { |
| int i = this.name.compareTo(other.name); |
| if (i != 0) { |
| return i; |
| } |
| } |
| |
| if (this.uniqueTag == null && other.uniqueTag == null) { |
| // not loners, so look at P2P view ID |
| if (this.vmViewId < other.vmViewId) { |
| return -1; |
| } else if (this.vmViewId > other.vmViewId) { |
| return 1; |
| } // else they're the same, so continue |
| } else if (this.uniqueTag == null) { |
| return -1; |
| } |
| else if (other.uniqueTag == null) { |
| return 1; |
| } |
| else { |
| int i = this.uniqueTag.compareTo(other.uniqueTag); |
| if (i != 0) { |
| return i; |
| } |
| } |
| |
| // purposely avoid comparing roles |
| // @todo Add durableClientAttributes to compare |
| return 0; |
| } |
| |
| @Override |
| public boolean equals(Object obj) |
| { |
| if (this == obj) { |
| return true; |
| } |
| // GemStone fix for 29125 |
| if ((obj == null) || !(obj instanceof InternalDistributedMember)) { |
| return false; |
| } |
| return compareTo((InternalDistributedMember)obj) == 0; |
| } |
| |
| @Override |
| public int hashCode() |
| { |
| int result = 0; |
| result = result + ipAddr.getIpAddress().hashCode(); |
| result = result + getPort(); |
| return result; |
| } |
| |
| private String shortName(String hostname) |
| { |
| if (hostname == null) |
| return "<null inet_addr hostname>"; |
| int index = hostname.indexOf('.'); |
| |
| if (index > 0 && !Character.isDigit(hostname.charAt(0))) |
| return hostname.substring(0, index); |
| else |
| return hostname; |
| } |
| |
| |
| /** the cached string description of this object */ |
| private transient String cachedToString; |
| |
| @Override |
| public String toString() |
| { |
| String result = cachedToString; |
| if (result == null) { |
| String host; |
| |
| InetAddress add = getIpAddress(); |
| if (add.isMulticastAddress()) |
| host = add.getHostAddress(); |
| else { |
| // host = shortName(add.getHostName()); |
| host = SocketCreator.resolve_dns? shortName(this.hostName) : this.hostName; |
| } |
| final StringBuilder sb = new StringBuilder(); |
| |
| sb.append(host); |
| |
| String myName = getName(); |
| if (vmPid > 0 || vmKind != DistributionManager.NORMAL_DM_TYPE || !"".equals(myName)) { |
| sb.append("("); |
| |
| if (!"".equals(myName)) { |
| sb.append(myName); |
| if (vmPid > 0) { |
| sb.append(':'); |
| } |
| } |
| |
| if (vmPid > 0) |
| sb.append(Integer.toString(vmPid)); |
| |
| String vmStr = ""; |
| switch (vmKind) { |
| case DistributionManager.NORMAL_DM_TYPE: |
| // vmStr = ":local"; // let this be silent |
| break; |
| case DistributionManager.LOCATOR_DM_TYPE: |
| vmStr = ":locator"; |
| break; |
| case DistributionManager.ADMIN_ONLY_DM_TYPE: |
| vmStr = ":admin"; |
| break; |
| case DistributionManager.LONER_DM_TYPE: |
| vmStr = ":loner"; |
| break; |
| default: |
| vmStr = ":<unknown:" + vmKind + ">"; |
| break; |
| } |
| sb.append(vmStr); |
| // for split-brain and security debugging we need to know if the |
| // member has the "can't be coordinator" bit set |
| // JGroupMember jgm = (JGroupMember)ipAddr; |
| // if (!jgm.getAddress().canBeCoordinator()) { |
| // sb.append("<p>"); |
| // } |
| sb.append(")"); |
| } |
| if (ipAddr.splitBrainEnabled()) { |
| if (ipAddr.canBeCoordinator()) { |
| sb.append("<ec>"); |
| } |
| } |
| if (this.vmViewId >= 0) { |
| sb.append("<v" + this.vmViewId + ">"); |
| } |
| sb.append(":"); |
| sb.append(getPort()); |
| |
| // if (dcPort > 0 && vmKind != DistributionManager.LONER_DM_TYPE) { |
| // sb.append("/"); |
| // sb.append(Integer.toString(dcPort)); |
| // } |
| |
| if (vmKind == DistributionManager.LONER_DM_TYPE) { |
| // add some more info that was added in 4.2.1 for loner bridge clients |
| // impact on non-bridge loners is ok |
| if (this.uniqueTag != null && this.uniqueTag.length() != 0) { |
| sb.append(":").append(this.uniqueTag); |
| } |
| if (this.name != null && this.name.length() != 0) { |
| sb.append(":").append(this.name); |
| } |
| } |
| |
| // add version if not current |
| if (this.version != Version.CURRENT.ordinal()) { |
| sb.append("(version:").append(Version.toString(this.version)) |
| .append(')'); |
| } |
| |
| // leave out Roles on purpose |
| |
| result = sb.toString(); |
| cachedToString = result; |
| } |
| return result; |
| } |
| |
| private void readVersion(int flags, DataInput in) throws IOException { |
| if ((flags & VERSION_MASK) != 0) { |
| this.version = Version.readOrdinal(in); |
| this.versionObj = Version.fromOrdinalNoThrow(this.version, false); |
| } |
| } |
| |
| /** |
| * For Externalizable |
| * |
| * @see Externalizable |
| */ |
| public void writeExternal(ObjectOutput out) throws IOException { |
| Assert.assertTrue(vmKind > 0); |
| |
| // do it the way we like |
| byte[] address = getIpAddress().getAddress(); |
| |
| out.writeInt(address.length); // IPv6 compatible |
| out.write(address); |
| out.writeInt(getPort()); |
| |
| DataSerializer.writeString(this.hostName, out); |
| |
| int flags = 0; |
| if (ipAddr.splitBrainEnabled()) flags |= SB_ENABLED_MASK; |
| if (ipAddr.canBeCoordinator()) flags |= COORD_ENABLED_MASK; |
| if (this.isPartial) flags |= PARTIAL_ID_MASK; |
| // always write product version but enable reading from older versions |
| // that do not have it |
| flags |= VERSION_MASK; |
| out.writeByte((byte)(flags & 0xff)); |
| |
| out.writeInt(dcPort); |
| out.writeInt(vmPid); |
| out.writeInt(vmKind); |
| out.writeInt(vmViewId); |
| DataSerializer.writeStringArray(this.groups, out); |
| |
| DataSerializer.writeString(this.name, out); |
| DataSerializer.writeString(this.uniqueTag, out); |
| DataSerializer.writeString(this.durableClientAttributes==null ? "" : this.durableClientAttributes.getId(), out); |
| DataSerializer.writeInteger(Integer.valueOf(this.durableClientAttributes==null ? 300 : this.durableClientAttributes.getTimeout()), out); |
| Version.writeOrdinal(out, this.version, true); |
| } |
| |
| /** |
| * For Externalizable |
| * |
| * @see Externalizable |
| */ |
| public void readExternal(ObjectInput in) |
| throws IOException, ClassNotFoundException { |
| // do it the way we like |
| int len = in.readInt(); // IPv6 compatible |
| byte addr[] = new byte[len]; |
| in.readFully(addr); |
| InetAddress inetAddr = InetAddress.getByAddress(addr); |
| int port = in.readInt(); |
| |
| this.hostName = DataSerializer.readString(in); |
| |
| int flags = in.readUnsignedByte(); |
| boolean sbEnabled = (flags & SB_ENABLED_MASK) != 0; |
| boolean elCoord = (flags & COORD_ENABLED_MASK) != 0; |
| this.isPartial = (flags & PARTIAL_ID_MASK) != 0; |
| |
| this.dcPort = in.readInt(); |
| this.vmPid = in.readInt(); |
| this.vmKind = in.readInt(); |
| this.vmViewId = in.readInt(); |
| this.groups = DataSerializer.readStringArray(in); |
| |
| this.name = DataSerializer.readString(in); |
| this.uniqueTag = DataSerializer.readString(in); |
| String durableId = DataSerializer.readString(in); |
| int durableTimeout = DataSerializer.readInteger(in).intValue(); |
| this.durableClientAttributes = new DurableClientAttributes(durableId, durableTimeout); |
| |
| readVersion(flags, in); |
| |
| ipAddr = MemberFactory.newNetMember(inetAddr, port, sbEnabled, elCoord, |
| new MemberAttributes(dcPort, vmPid, vmKind, vmViewId, name, groups, durableClientAttributes)); |
| ((JGroupMember)ipAddr).getAddress().setVersionOrdinal(this.version); |
| |
| Assert.assertTrue(this.vmKind > 0); |
| } |
| |
| public int getDSFID() { |
| return DISTRIBUTED_MEMBER; |
| } |
| |
| public void toData(DataOutput out) throws IOException { |
| Assert.assertTrue(vmKind > 0); |
| // [bruce] disabled to allow post-connect setting of the port for loner systems |
| // Assert.assertTrue(getPort() > 0); |
| // if (this.getPort() == 0) { |
| // InternalDistributedSystem.getLoggerI18n().warning(LocalizedStrings.DEBUG, |
| // "Serializing ID with zero port", new Exception("Stack trace")); |
| // } |
| |
| // NOTE: If you change the serialized format of this class |
| // then bump Connection.HANDSHAKE_VERSION since an |
| // instance of this class is sent during Connection handshake. |
| DataSerializer.writeInetAddress(getIpAddress(), out); |
| out.writeInt(getPort()); |
| |
| DataSerializer.writeString(this.hostName, out); |
| |
| int flags = 0; |
| if (ipAddr.splitBrainEnabled()) flags |= SB_ENABLED_MASK; |
| if (ipAddr.canBeCoordinator()) flags |= COORD_ENABLED_MASK; |
| if (this.isPartial) flags |= PARTIAL_ID_MASK; |
| // always write product version but enable reading from older versions |
| // that do not have it |
| flags |= VERSION_MASK; |
| out.writeByte((byte)(flags & 0xff)); |
| |
| out.writeInt(dcPort); |
| out.writeInt(vmPid); |
| out.writeByte(vmKind); |
| DataSerializer.writeStringArray(this.groups, out); |
| |
| DataSerializer.writeString(this.name, out); |
| if (this.vmKind == DistributionManager.LONER_DM_TYPE) { |
| DataSerializer.writeString(this.uniqueTag, out); |
| } else { // added in 6.5 for unique identifiers in P2P |
| DataSerializer.writeString(String.valueOf(this.vmViewId), out); |
| } |
| DataSerializer.writeString(this.durableClientAttributes==null ? "" : this.durableClientAttributes.getId(), out); |
| DataSerializer.writeInteger(Integer.valueOf(this.durableClientAttributes==null ? 300 : this.durableClientAttributes.getTimeout()), out); |
| Version.writeOrdinal(out, this.version, true); |
| } |
| |
| public void toDataPre_GFE_7_1_0_0(DataOutput out) throws IOException { |
| Assert.assertTrue(vmKind > 0); |
| // [bruce] disabled to allow post-connect setting of the port for loner systems |
| // Assert.assertTrue(getPort() > 0); |
| // if (this.getPort() == 0) { |
| // InternalDistributedSystem.getLoggerI18n().warning(LocalizedStrings.DEBUG, |
| // "Serializing ID with zero port", new Exception("Stack trace")); |
| // } |
| |
| // NOTE: If you change the serialized format of this class |
| // then bump Connection.HANDSHAKE_VERSION since an |
| // instance of this class is sent during Connection handshake. |
| DataSerializer.writeInetAddress(getIpAddress(), out); |
| out.writeInt(getPort()); |
| |
| DataSerializer.writeString(this.hostName, out); |
| |
| int flags = 0; |
| if (ipAddr.splitBrainEnabled()) flags |= SB_ENABLED_MASK; |
| if (ipAddr.canBeCoordinator()) flags |= COORD_ENABLED_MASK; |
| if (this.isPartial) flags |= PARTIAL_ID_MASK; |
| out.writeByte((byte)(flags & 0xff)); |
| |
| out.writeInt(dcPort); |
| out.writeInt(vmPid); |
| out.writeByte(vmKind); |
| DataSerializer.writeStringArray(this.groups, out); |
| |
| DataSerializer.writeString(this.name, out); |
| if (this.vmKind == DistributionManager.LONER_DM_TYPE) { |
| DataSerializer.writeString(this.uniqueTag, out); |
| } else { // added in 6.5 for unique identifiers in P2P |
| DataSerializer.writeString(String.valueOf(this.vmViewId), out); |
| } |
| DataSerializer.writeString(this.durableClientAttributes==null ? "" : this.durableClientAttributes.getId(), out); |
| DataSerializer.writeInteger(Integer.valueOf(this.durableClientAttributes==null ? 300 : this.durableClientAttributes.getTimeout()), out); |
| |
| } |
| |
| public void fromData(DataInput in) |
| throws IOException, ClassNotFoundException { |
| // do it the way we like it. |
| InetAddress inetAddr = DataSerializer.readInetAddress(in); |
| int port = in.readInt(); |
| |
| this.hostName = DataSerializer.readString(in); |
| this.hostName = SocketCreator.resolve_dns? SocketCreator.getCanonicalHostName(inetAddr, hostName) : inetAddr.getHostAddress(); |
| |
| int flags = in.readUnsignedByte(); |
| boolean sbEnabled = (flags & SB_ENABLED_MASK) != 0; |
| boolean elCoord = (flags & COORD_ENABLED_MASK) != 0; |
| this.isPartial = (flags & PARTIAL_ID_MASK) != 0; |
| |
| this.dcPort = in.readInt(); |
| this.vmPid = in.readInt(); |
| this.vmKind = in.readUnsignedByte(); |
| this.groups = DataSerializer.readStringArray(in); |
| |
| this.name = DataSerializer.readString(in); |
| if (this.vmKind == DistributionManager.LONER_DM_TYPE) { |
| this.uniqueTag = DataSerializer.readString(in); |
| } else { |
| String str = DataSerializer.readString(in); |
| if (str != null) { // backward compatibility from earlier than 6.5 |
| this.vmViewId = Integer.parseInt(str); |
| } |
| } |
| |
| String durableId = DataSerializer.readString(in); |
| int durableTimeout = DataSerializer.readInteger(in).intValue(); |
| this.durableClientAttributes = new DurableClientAttributes(durableId, durableTimeout); |
| |
| readVersion(flags, in); |
| |
| MemberAttributes attr = new MemberAttributes(this.dcPort, this.vmPid, |
| this.vmKind, this.vmViewId, this.name, this.groups, this.durableClientAttributes); |
| ipAddr = MemberFactory.newNetMember(inetAddr, port, sbEnabled, elCoord, attr); |
| ((JGroupMember)ipAddr).getAddress().setVersionOrdinal(this.version); |
| |
| synchPayload(); |
| |
| Assert.assertTrue(this.vmKind > 0); |
| // Assert.assertTrue(getPort() > 0); |
| } |
| |
| public void fromDataPre_GFE_7_1_0_0(DataInput in) throws IOException, ClassNotFoundException { |
| // do it the way we like it. |
| InetAddress inetAddr = DataSerializer.readInetAddress(in); |
| int port = in.readInt(); |
| |
| this.hostName = DataSerializer.readString(in); |
| this.hostName = SocketCreator.resolve_dns? SocketCreator.getCanonicalHostName(inetAddr, hostName) : inetAddr.getHostAddress(); |
| |
| int flags = in.readUnsignedByte(); |
| boolean sbEnabled = (flags & SB_ENABLED_MASK) != 0; |
| boolean elCoord = (flags & COORD_ENABLED_MASK) != 0; |
| this.isPartial = (flags & PARTIAL_ID_MASK) != 0; |
| |
| this.dcPort = in.readInt(); |
| this.vmPid = in.readInt(); |
| this.vmKind = in.readUnsignedByte(); |
| this.groups = DataSerializer.readStringArray(in); |
| |
| this.name = DataSerializer.readString(in); |
| if (this.vmKind == DistributionManager.LONER_DM_TYPE) { |
| this.uniqueTag = DataSerializer.readString(in); |
| } else { |
| String str = DataSerializer.readString(in); |
| if (str != null) { // backward compatibility from earlier than 6.5 |
| this.vmViewId = Integer.parseInt(str); |
| } |
| } |
| |
| String durableId = DataSerializer.readString(in); |
| int durableTimeout = DataSerializer.readInteger(in).intValue(); |
| this.durableClientAttributes = new DurableClientAttributes(durableId, durableTimeout); |
| |
| MemberAttributes attr = new MemberAttributes(this.dcPort, this.vmPid, |
| this.vmKind, this.vmViewId, this.name, this.groups, this.durableClientAttributes); |
| ipAddr = MemberFactory.newNetMember(inetAddr, port, sbEnabled, elCoord, attr); |
| |
| synchPayload(); |
| |
| Assert.assertTrue(this.vmKind > 0); |
| } |
| |
| /** this writes just the parts of the ID that are needed for comparisons and communications */ |
| public static InternalDistributedMember readEssentialData(DataInput in) |
| throws IOException, ClassNotFoundException { |
| final InternalDistributedMember mbr = new InternalDistributedMember(); |
| mbr._readEssentialData(in); |
| return mbr; |
| } |
| |
| private void _readEssentialData(DataInput in) |
| throws IOException, ClassNotFoundException { |
| this.isPartial = true; |
| InetAddress inetAddr = DataSerializer.readInetAddress(in); |
| int port = in.readInt(); |
| |
| this.hostName = SocketCreator.resolve_dns? SocketCreator.getHostName(inetAddr) : inetAddr.getHostAddress(); |
| |
| int flags = in.readUnsignedByte(); |
| boolean sbEnabled = (flags & SB_ENABLED_MASK) != 0; |
| boolean elCoord = (flags & COORD_ENABLED_MASK) != 0; |
| |
| this.vmKind = in.readUnsignedByte(); |
| |
| |
| if (this.vmKind == DistributionManager.LONER_DM_TYPE) { |
| this.uniqueTag = DataSerializer.readString(in); |
| } else { |
| String str = DataSerializer.readString(in); |
| if (str != null) { // backward compatibility from earlier than 6.5 |
| this.vmViewId = Integer.parseInt(str); |
| } |
| } |
| |
| this.name = DataSerializer.readString(in); |
| |
| MemberAttributes attr = new MemberAttributes(this.dcPort, this.vmPid, |
| this.vmKind, this.vmViewId, this.name, this.groups, this.durableClientAttributes); |
| ipAddr = MemberFactory.newNetMember(inetAddr, port, sbEnabled, elCoord, attr); |
| |
| synchPayload(); |
| } |
| |
| |
| public void writeEssentialData(DataOutput out) throws IOException { |
| Assert.assertTrue(vmKind > 0); |
| DataSerializer.writeInetAddress(getIpAddress(), out); |
| out.writeInt(getPort()); |
| |
| int flags = 0; |
| if (ipAddr.splitBrainEnabled()) flags |= SB_ENABLED_MASK; |
| if (ipAddr.canBeCoordinator()) flags |= COORD_ENABLED_MASK; |
| flags |= PARTIAL_ID_MASK; |
| out.writeByte((byte)(flags & 0xff)); |
| |
| // out.writeInt(dcPort); |
| out.writeByte(vmKind); |
| |
| if (this.vmKind == DistributionManager.LONER_DM_TYPE) { |
| DataSerializer.writeString(this.uniqueTag, out); |
| } else { // added in 6.5 for unique identifiers in P2P |
| DataSerializer.writeString(String.valueOf(this.vmViewId), out); |
| } |
| // write name last to fix bug 45160 |
| DataSerializer.writeString(this.name, out); |
| } |
| |
| /** |
| * [GemStone] Set the direct channel port |
| */ |
| public void setDirectChannelPort(int p) |
| { |
| dcPort = p; |
| synchPayload(); |
| } |
| |
| /** |
| * Set the membership port. This is done in loner systems using |
| * client/server connection information to help form a unique ID |
| */ |
| public void setPort(int p) { |
| assert this.vmKind == DistributionManager.LONER_DM_TYPE; |
| this.ipAddr.setPort(p); |
| synchPayload(); |
| cachedToString = null; |
| } |
| |
| /** drop the cached toString rep of this ID */ |
| public void dropCachedString() { |
| this.cachedToString = null; |
| } |
| |
| public String getHost() { |
| return this.ipAddr.getIpAddress().getCanonicalHostName(); |
| } |
| |
| public int getProcessId() { |
| return this.vmPid; |
| } |
| |
| public String getId() { |
| return toString(); |
| } |
| /*if (this.ipAddr == null) { |
| return "<null>"; |
| } |
| else { |
| StringBuffer sb = new StringBuffer(); |
| InetAddress addr = this.ipAddr.getIpAddress(); |
| if(addr.isMulticastAddress()) { |
| sb.append(addr.getHostAddress()); |
| } else { |
| appendShortName(addr.getHostName(), sb); |
| } |
| if (this.vmPid != 0) { |
| sb.append("("); |
| sb.append(this.vmPid); |
| sb.append(")"); |
| } |
| sb.append(":"); |
| sb.append(this.ipAddr.getPort()); |
| return sb.toString(); |
| } |
| } |
| |
| // Helper method for getId()... copied from IpAddress. |
| private void appendShortName(String hostname, StringBuffer sb) { |
| if (hostname == null) return; |
| int index = hostname.indexOf('.'); |
| if(index > 0 && !Character.isDigit(hostname.charAt(0))) { |
| sb.append(hostname.substring(0, index)); |
| } else { |
| sb.append(hostname); |
| } |
| }*/ |
| |
| public final Version getVersionObject() { |
| return this.versionObj; |
| } |
| |
| @Override |
| public Version[] getSerializationVersions() { |
| return dsfidVersions; |
| } |
| |
| |
| @Override |
| public int getSizeInBytes() { |
| |
| int size = 0; |
| |
| // ipaddr: 1 byte length + 4 bytes (IPv4) or 16 bytes (IPv6) |
| if (ipAddr.getIpAddress() instanceof Inet4Address){ |
| size += 5; |
| } else { |
| size += 17; |
| } |
| |
| // port: 4 bytes |
| // flags: 1 byte |
| //vmKind: 1 byte |
| size += 6; |
| |
| // viewID: String(1+1+numchars) |
| size += (2+ String.valueOf(this.vmViewId).length()); |
| |
| // empty name: String(1+1) |
| size += 2; |
| |
| return size; |
| } |
| } |