001: /*
002: * JBoss, Home of Professional Open Source
003: * Copyright 2005, JBoss Inc., and individual contributors as indicated
004: * by the @authors tag. See the copyright.txt in the distribution for a
005: * full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022:
023: package org.jboss.ha.framework.server;
024:
025: import java.net.InetAddress;
026: import java.rmi.dgc.VMID;
027: import java.rmi.server.UID;
028:
029: import javax.management.Attribute;
030: import javax.management.AttributeList;
031: import javax.management.InstanceNotFoundException;
032: import javax.management.MBeanServer;
033: import javax.management.ReflectionException;
034:
035: import org.jboss.logging.Logger;
036: import org.jboss.mx.util.MBeanServerLocator;
037: import org.jboss.naming.NamingServiceMBean;
038: import org.jboss.system.ServiceMBean;
039: import org.jboss.system.server.ServerConfigUtil;
040: import org.jgroups.Channel;
041: import org.jgroups.Event;
042: import org.jgroups.mux.MuxChannel;
043: import org.jgroups.stack.IpAddress;
044:
045: /**
046: * Extension to the JGroups JChannelFactory that supports the addition
047: * of "additional_data" to the channel config. Needed until logical
048: * addresses are supported in JGroups.
049: *
050: * @author <a href="mailto://brian.stansberry@jboss.com">Brian Stansberry</a>
051: * @version $Revision$
052: */
053: public class JChannelFactory extends org.jgroups.jmx.JChannelFactory {
054: protected static Logger log = Logger
055: .getLogger(JChannelFactory.class);
056:
057: private InetAddress nodeAddress;
058: private String nodeName;
059:
060: /**
061: * Overrides the superclass version by generating a unique node id
062: * and passing it down the Channel as additional_data.
063: */
064: public Channel createMultiplexerChannel(String stack_name,
065: String id, boolean register_for_state_transfer,
066: String substate_id) throws Exception {
067: Channel channel = super .createMultiplexerChannel(stack_name,
068: id, register_for_state_transfer, substate_id);
069:
070: setChannelUniqueId(channel);
071:
072: return channel;
073: }
074:
075: /**
076: * Overrides the superclass version by generating a unique node id
077: * and passing it down the Channel as additional_data.
078: */
079: public Channel createMultiplexerChannel(String stack_name, String id)
080: throws Exception {
081: Channel channel = super
082: .createMultiplexerChannel(stack_name, id);
083:
084: setChannelUniqueId(channel);
085:
086: return channel;
087: }
088:
089: public InetAddress getNodeAddress() {
090: return nodeAddress;
091: }
092:
093: public void setNodeAddress(InetAddress nodeAddress) {
094: this .nodeAddress = nodeAddress;
095: }
096:
097: public String getNodeName() {
098: return nodeName;
099: }
100:
101: public void setNodeName(String nodeName) {
102: this .nodeName = nodeName;
103: }
104:
105: private void setChannelUniqueId(Channel channel) throws Exception {
106: IpAddress address = (IpAddress) channel.getLocalAddress();
107: if (address == null) {
108: // We push the independent name in the protocol stack before connecting to the cluster
109: if (this .nodeName == null || "".equals(this .nodeName)) {
110: this .nodeName = generateUniqueNodeName();
111: }
112:
113: log.debug("Passing unique node id " + nodeName
114: + " to the channel as additional data");
115:
116: java.util.HashMap staticNodeName = new java.util.HashMap();
117: staticNodeName.put("additional_data", this .nodeName
118: .getBytes());
119: channel.down(new Event(Event.CONFIG, staticNodeName));
120:
121: } else if (address.getAdditionalData() == null) {
122: Channel testee = channel;
123: if (channel instanceof MuxChannel) {
124: testee = ((MuxChannel) channel).getChannel();
125: }
126:
127: if (testee.isConnected()) {
128: throw new IllegalStateException(
129: "Underlying JChannel was "
130: + "connected before additional_data was set");
131: }
132: } else if (this .nodeName == null || "".equals(this .nodeName)) {
133: this .nodeName = new String(address.getAdditionalData());
134: log
135: .warn("Field nodeName was not set but mux channel already had "
136: + "additional data -- setting nodeName to "
137: + nodeName);
138: }
139: }
140:
141: private String generateUniqueNodeName() throws Exception {
142: // we first try to find a simple meaningful name:
143: // 1st) "local-IP:JNDI_PORT" if JNDI is running on this machine
144: // 2nd) "local-IP:JMV_GUID" otherwise
145: // 3rd) return a fully GUID-based representation
146: //
147:
148: // Before anything we determine the local host IP (and NOT name as this could be
149: // resolved differently by other nodes...)
150:
151: // But use the specified node address for multi-homing
152:
153: String hostIP = null;
154: InetAddress address = ServerConfigUtil
155: .fixRemoteAddress(nodeAddress);
156: if (address == null) {
157: log
158: .debug("unable to create a GUID for this cluster, check network configuration is correctly setup (getLocalHost has returned an exception)");
159: log.debug("using a full GUID strategy");
160: return new VMID().toString();
161: } else {
162: hostIP = address.getHostAddress();
163: }
164:
165: // 1st: is JNDI up and running?
166: //
167: try {
168: MBeanServer server = MBeanServerLocator.locateJBoss();
169: AttributeList al = server.getAttributes(
170: NamingServiceMBean.OBJECT_NAME, new String[] {
171: "State", "Port" });
172:
173: int status = ((Integer) ((Attribute) al.get(0)).getValue())
174: .intValue();
175: if (status == ServiceMBean.STARTED) {
176: // we can proceed with the JNDI trick!
177: int port = ((Integer) ((Attribute) al.get(1))
178: .getValue()).intValue();
179: return hostIP + ":" + port;
180: } else {
181: log
182: .debug("JNDI has been found but the service wasn't started so we cannot "
183: + "be entirely sure we are the only one that wants to use this PORT "
184: + "as a GUID on this host.");
185: }
186:
187: } catch (InstanceNotFoundException e) {
188: log
189: .debug("JNDI not running here, cannot use this strategy to find a node GUID for the cluster");
190: } catch (ReflectionException e) {
191: log
192: .debug("JNDI querying has returned an exception, cannot use this strategy to find a node GUID for the cluster");
193: }
194:
195: // 2nd: host-GUID strategy
196: //
197: String uid = new UID().toString();
198: return hostIP + ":" + uid;
199: }
200:
201: }
|